Synopsis: | Derive from more than one base class with the same parent with care |
Language: | C++ |
Severity Level: | 9 |
Category: | Object Oriented Programming |
Description: |
This rule prevents potential problems caused by multiple derived classes of a common base class. The example below shows why this is problematic: class Base { public: // ... protected: int data_; }; class Der1 : public Base { /*...*/ }; class Der2 : public Base { /*...*/ }; class Join : public Der1, public Der2 { public: void method() { data_ = 1; // Bad: this is ambiguous; see below } }; int main() { Join* j = new Join(); Base* b = j; // Bad: this is ambiguous; see below } The key is to realize that Base is inherited twice, which means any data members declared in Base, such as data_ above, will appear twice within a Join object. This can create ambiguities: which data_ did you want to change? For the same reason the conversion from Join* to Base*, or from Join& to Base&, is ambiguous: which Base class subobject did you want? One way to avoid this problem is using virtual inheritance. This comes down to derive virtually from the Base class: class Base { public: // ... protected: int data_; }; class Der1 : public virtual Base { public: // ... }; class Der2 : public virtual Base { public: // ... }; class Join : public Der1, public Der2 { public: void method() { data_ = 1; // Good: this is now unambiguous } }; int main() { Join* j = new Join(); Base* b = j; // Good: this is now unambiguous } Another way to avoid these common base class problems is to make sure the base class doesn't contain members, is virtual and has a default constructor. |
Literature References: |
ISO C++ Where in a hierarchy should I use virtual inheritance? |