10. Derived Classes
10.1 Multiple Base Classes
10.1.1 Ensure that access to base class subobjects does not require explicit disambiguation
A class inherited more than once in a hierarchy, and not inherited virtually in all paths will result in multiple base class subobjects being present in instances of the derived object type. Such objects require that the developer explicitly select which base class to use when accessing members. The result is a hierarchy that is harder to understand and maintain.
class Base { public: void foo (); }; class Derived_left: public Base {}; class Derived_right: public Base {}; // @@- Non-Compliant: 2 subobjects for 'Base' -@@ class Derived: public Derived_left, public Derived_right { }; void test() { Derived d; // ambiguous - Derived_left::Base::foo or Derived_right::Base::foo? d.foo (); }
The example above can be made to comply with this rule by using virtual inheritance:
class Base {}; class Derived_left: public virtual Base {}; class Derived_right: public virtual Base {}; class Derived: public Derived_left, public Derived_right // @@+ Compliant +@@ { };
References
- HIC++ v3.3 – 3.3.15
10.2 Virtual Functions
10.2.1 Use the override special identifier when overriding a virtual function
The override special identifier is a directive to the compiler to check that the function is overriding a base class member. This will ensure that a change in the signature of the virtual function will generate a compiler error.
#include <cstdint> class A { public: virtual void f(int64_t); }; class B : public A { public: void f(int32_t) override; // @@+ Compliant: Compile Error +@@ };
Note: The following was considered good C++03 style:
#include <cstdint> class A { public: virtual void f(int32_t); }; class B : public A { public: virtual void f(int32_t); // @@- Non-Compliant -@@ }; void f(A & a) { a.f(0); // Results in (*@\color{blue}{B::f}@*) being called }
However, this provided no guarantees and no additional checking by the compiler if the function signature was changed.
#include <cstdint> class A { public: virtual void f(int64_t); }; class B : public A { public: virtual void f(int32_t); // @@- Non-Compliant -@@ }; void f(A & a) { a.f(0); // Results in (*@\color{red}{A::f}@*) being called!!!! }
References
- HIC++ v3.3 – 3.3.16
10.3 Abstract Classes
10.3.1 Ensure that a derived class has at most one base class which is not an interface class
An interface class has the following properties:
- All public functions are pure virtual functions or getters.
- There are no public or protected data members.
- It contains at most one private data member of integral or enumerated type.
Inheriting from two or more base classes that are not interfaces, is rarely correct. It also exposes the derived class to multiple implementations, with the risk that subsequent changes to any of the base classes may invalidate the derived class. On the other hand, it is reasonable that a concrete class may implement more than one interface.
#include <cstdint> class A { public: virtual ~A () = 0; virtual void foo () = 0; }; class B { public: virtual ~B () = 0; virtual void bar () = 0; }; class C { public: C (); void foo (); virtual ~C (); private: int32_t m_i; }; // @@+ Compliant +@@ class D: public A, public B, public C { public: ~ D(); }; class E { public: E (); }; // @@- Non-Compliant -@@ class F : public E, public D { };
References
- JSF AV C++ Rev C – 87
- JSF AV C++ Rev C – 88
- HIC++ v3.3 – 3.4.6