在C ++中定义虚拟get和set函数被认为是一种好习惯吗?

时间:2015-02-18 15:55:14

标签: c++ function polymorphism virtual

如果我有一个简单的2级类层次结构,例如,这个:

// level 1
class Spare_Part{
private:
    string name;
    double price;
public:
    Spare_Part();
    string getName() { return name; }
    double getPrice() { return price; }
    virtual int getQuantity() { return -1; }; // may also define it as pure virtual
};
//level 2
class On_hand : public Spare_Part{
private:
    int quantity;
    string location;
public:
    On_hand();
    int getQuantity(){ return quantity; }
};

我希望能够访问会员数量'在班级' On_hand'使用指向基类的指针' Spare_part',所以我制作了' getQuantity'功能虚拟。代码工作正常,但是,我觉得我不应该有一个get / set函数(即使是虚函数)来访问在层次结构中某处定义的成员。这真的被认为是一种不好的做法,应该通过重新设计类来避免这种做法吗? 编辑:整个层次结构有点复杂。除了' On_hand'通过签约供应商提供零件类。我的假设是,我无法知道供应商可以获得多少零件,这就是为什么数量和数量相同的原因。不包含在基类中。

3 个答案:

答案 0 :(得分:4)

在这种情况下,是的,这是不好的做法;如果在getQuantity上调用Spare_Part没有意义,那就不应该编译。它绝对不应该只返回一个标志值。

可能需要重新设计课程。应该使用多态来模拟 is-a 关系,但是您的使用主要是将更多数据标记到类中。您应该使用合成,可能会创建一个Part_Store类,其中包含Spare_Part,数量和位置。

答案 1 :(得分:1)

让我们尝试整理出来。

让基类调用其派生类来读取属性没有错。有些情况下,已知基类的每个实现都必须具有属性,并且基类提供了一些需要该属性的功能,并且在所有合理的实现中都是相同的,除了该属性。 在这种情况下,这样做绝对没有错。

作为替代方案,如果您确定在任何合理的实现中始终使用简单的固定类型变量来实现属性,您只需将受保护的变量添加到基类中,然后让实现写入它。

这完全取决于您需要多大的灵活性。

在您的情况下,我认为您的概念继承模型存在缺陷,这种情况会使您的情况失效。

您说的是On_hand来自Spare_Part,根据定义,这意味着每个On_hand都是Spare_Part。这对我来说听起来很怪异,因为他现在正在&#34;听起来更像是备件的质量,而不是它的特殊情况。也许最好将optional<On_Hand>添加到Spare_Part

或者,更好的是,我怀疑你想要像

这样的东西
struct On_Hand_Info { int quantity; string location; };
std::map<Spare_Part, On_Hand_Info> on_hand;

修改

看到你的最新更新,也许你应该做类似的事情:

struct IRetrievalInformation {
  virtual int getQuantity() const=0;
};

class SparePart{
  string name;
  double price;
  std::unique_ptr<IRetrievalInformation> retinfo;
public:
  Spare_Part();
  string const& getName() const { return name; }
  double getPrice() const { return price; }
  IRetrievalInformation const& getRetrievalInformation() const {
    assert(retinfo);
    return *retinfo;
  }
  IRetrievalInformation& getRetrievalInformation() {
    return const_cast<IRetrievalInformation&>(
      const_cast<SparePart const*>(this)->getRetrievalInformation()
    );
  }
};

class OnHandRetrieval : public IRetrievalInformation {
  int quantity;
  string location;
public:
  On_hand();
  int getQuantity() const final override { return quantity; }
};
PS:为了上帝的缘故,不要使用两个 camelcase和下划线。

答案 2 :(得分:0)

IMO,getter和setter必须被认为是一种不好的做法,甚至在几乎所有情况下都是反模式。使用OOP的全部意义在于隐藏实现细节(不仅如此,这也是其中之一)。 Getter / setter旨在公开实现细节,因此它破坏了OOP原则之一。最后,如果你使用getter / setter,为什么不使用旧的普通C结构?在这种情况下,课程对结构没有任何好处。

嗯, 的情况下,getter / setter可能看起来不错。关键是,有太多的程序员使用它们来替换结构。原因通常是 - 他们不了解如何以OOP方式设计应用程序。

在您的情况下,您不需要吸气剂/安装者。试想一下你将如何进一步使用这门课程。是否会有任何额外的功能或只是存储一些数据?如果是这样,也许只使用POD结构?

进一步阅读:

[1] http://www.javaworld.com/article/2073723/core-java/why-getter-and-setter-methods-are-evil.html

[2] http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html

[3] http://typicalprogrammer.com/doing-it-wrong-getters-and-setters/

[4] Why use getters and setters?

[5] http://berryllium.nl/2011/02/getters-and-setters-evil-or-necessary-evil/