views:

829

answers:

5

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.

A: 

Hi,

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

3DH
+7  A: 

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.

iain
+1 This is also summarised on the C++ FAQ Lite http://www.new-brunswick.net/workshop/c++/faq/multiple-inheritance.html#faq-25.8
Andrew Walker
I don' think any of that is true.
Martin York
@Martin: sadly, it is...
+1  A: 

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.

David Coufal
If you can get a copy of "Effective C++", read item 20: "Avoid data members in public interfaces".
quark
Right, I agree with this. I'm not suggesting that data members be public.In any case, I misunderstood the question, and think iain's answer is good.
David Coufal
A: 

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
};
You mean if I didn't call virtual base ctor explicitly it will not be called when I create the derived object?
Jack
You _have_ to call the virtual base class ctor in _each_ derived ctor's implementation, the compiler won't let you get away with it otherwise. The only exception: if the virtual base has a default ctor, that one's called when you don't explicitly call another one.
A: 

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.
peterchen