Virtual base class data members

2019-02-12 22:58发布

Why it is recommended not to have data members in virtual base class?

What about function members? If I have a task common to all derived classes is it OK for virtual base class to do the task or should the derived inherit from two classed - from virtual interface and plain base that do the task?

Thanks.

5条回答
再贱就再见
2楼-- · 2019-02-12 23:33

a) members should be private - so you may get problems using them in derived classes (so you have to add getter and setter methods, which blow up your interface)

b) don't declare things you currently don't use - declare variables only in classes which access/use them

c) virtual base classes should only contain the interfaces/virtual methods, nothing more

I hope that helps a little bit, even if my reasons are not perfect and complete :)

ciao, Chris

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-02-12 23:44

I've never seen this recommendation.

A class is a set of closely related functions and data. The purpose of a base class is to have a common set of functions and data that are available for reuse by derived classes.

I think restricting yourself to not have data members or non-pure virtual functions in base classes will reduce the amount of code reuse, which leads to less reliable code in the long run.

查看更多
Root(大扎)
4楼-- · 2019-02-12 23:46

The core advice is to have a default-constructor in the virtual base. If you don't, then every most-derived class (ie. any subclass) must call the virtual base ctor explicitly, and that leads to angry colleagues knocking on your office door...

class VirtualBase {
public:
    explicit VirtualBase( int i ) : m_i( i ) {}
    virtual ~VirtualBase() {}

private:
    int m_i;
};

class Derived : public virtual VirtualBase {
public:
    Derived() : VirtualBase( 0 ) {} // ok, this is to be expected
};

class DerivedDerived : public Derived { // no VirtualBase visible
public:
    DerivedDerived() : Derived() {} // ok? no: error: need to explicitly
                                    // call VirtualBase::VirtualBase!!
    DerivedDerived() : VirtualBase( 0 ), Derived() {} // ok
};
查看更多
狗以群分
5楼-- · 2019-02-12 23:49

As a practice you should only use virtual inheritance to define interfaces as they are usually used with multiple inheritance to ensure that only one version of the class is present in the derived class. And pure interfaces are the safest form of multiple inheritance. Of course if you know what you are doing you can use multiple inheritance as you like, but it can result in brittle code if you are not careful.

The biggest drawback with virtual inheritance is if their constructors take parameters. If you have to pass parameters to the constructor of a virtual base class you force all derived classes to explicitly call the constructor (they cannot rely on a base class calling the constructor).

The only reason I can see for your explicit advise is that data in your virtual base class these might require constructor parameters.

Edit I did some home work after Martin's comment, thank Marin. The first line is not quite true:

As a practice you should only use virtual inheritance to define interfaces as they are usually used with multiple inheritance to ensure that only one version of the class is present in the derived class.

Virtual inheritance makes no difference if the base class is a pure interface (except for slightly different compiler errors, in vc8, if all the methods are not implemented). It only makes a real difference if the base class has data, in this case you end up with a diamond rather than a U shape

Non virtual    virtual
  A     A          A
  |     |        /   \
  B     C       B     C
   \   /         \   /
     D             D

In the virtual case B and C share the same copy of A.

However I still agree with everything else about pure interfaces being the safest form of multiple inheritance, even if they don't require virtual inheritance. And the fact that constructor parameters and virtual inheritance are a pain.

查看更多
ゆ 、 Hurt°
6楼-- · 2019-02-12 23:53

All-abtract base classes that are used to simulate interfaces in C++ should not have data members - because they are describing an interface, and instance state is an implementation detail.

Other than that, base classes containing virtual functions may well have data members. The usual rules apply, though:

  • make them as hidden as possible, and use getters and setters if you need to preserve class invariants.
    (There's a loophole in here: if there's no invariant associated with the member, i.e. it may assume any possible value at any given time, you might make it public. However, this denies a derived class adding an invariant.
  • Design for inheritance: the contract of your class should define the responsibilities and possibilities of a derived class, what it needs/can overwrite for what purpose.
查看更多
登录 后发表回答