Is it considered a good practice to define virtual get and set functions in C++?

佐手、 提交于 2021-01-27 06:28:56

问题


If I have a simple 2 level class hierarchy as, for instance, this one:

// 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; }
};

I want to have access to the member 'quantity' in the class 'On_hand' using a pointer to the base class 'Spare_part', so I made the 'getQuantity' function a virtual one. The code works fine, however, I have a feeling that I shouldn't have a get/set function (even though a virtual one) to access a member that is defined somewhere down the hierarchy. Is this really considered a bad practice that should be avoided by, for example, redesign of the classes? Edit:The whole hierarchy is a little bit more complex. Alongside the 'On_hand' class there is class for parts available through contracted suppliers. The assumption is that I wouldn't be able to know how many parts are available through the suppliers and that is why 'quantity' is not included in the base class.


回答1:


In this case, yes, this is bad practice; if it doesn't make sense to call getQuantity on a Spare_Part, it shouldn't compile. It should definitely not just return a flag value.

A redesign of your classes is probably necessary. Polymorphism should be used to model an is-a relationship, but your use is mostly to tag more data onto the class. You should use composition instead, perhaps making a Part_Store class which contains a Spare_Part, the quantity and location.




回答2:


Let's try sorting things out.

There's nothing wrong in having a base calling its derived class to read a property. There are cases when it's known that every implementation of a base class must have a property, and the base class offers some functionalities that require that property, and that would be the same in all reasonable implementation, except for that property. In such cases, there's absolutely nothing wrong in doing that.

As an alternative, if you're really sure that property is always going to be implemented with a simple fixed-type variable in any reasonable implementation, you can just add a protected variable to the base class, and let the implementations write to it.

It's all a matter of how much flexibility you need.

In your case, I think your conceptual inheritance model is flawed, which kind of empties your case of any meaning.

You are saying that On_hand derives from Spare_Part, which means, by definition, that every On_hand is a Spare_Part. This sounds weird to me, as being "on hand" sounds more like a quality of the spare part, than a special case of it. Maybe it'd be better to add an optional<On_Hand> to Spare_Part.

Or, even better, I suspect you want something like

struct On_Hand_Info { int quantity; string location; };
std::map<Spare_Part, On_Hand_Info> on_hand;

EDIT

Seen your last updates, maybe you should do something like:

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: for God's sake, don't use both camelcase and underscores.




回答3:


IMO, getters and setters must be considered as a bad practice and even an anti-pattern in almost all cases. The whole point of using OOP is to conceal implementation details (well, not only this, but this is also among others). Getters/setters are intended to expose implementation details, hence it ruins one of OOP principles. In the end, why not using old plain C structs, if you are using getters/setters? In such case, classes don't have any advantages over structs.

Well, there are cases when getters/setters may look good. The point is, there are too many programmers use them as replacement for structs. And the reason usually -- they don't understand how to design application in OOP manner.

In your case you don't need getters/setters. Just think about how you are gonna use this class further. Is it gonna have any extra functionality or just store some data? If so, maybe just use POD structs?

Further reading:

[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/



来源:https://stackoverflow.com/questions/28587909/is-it-considered-a-good-practice-to-define-virtual-get-and-set-functions-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!