[Home]
[Edit this page]
[Recent Changes]
[Special Pages]
[Help]
CppInheritance
Prefer composition to inheritance [1].
In the example below, there is a base class called Base, having a method to say hello. It has a derived class called Derived, having a method to say bye. The derived class inherits the method to say hello:
[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
CppInheritance
(C++) Inheritance
When a class is a derived class, it inherits the methods of its base class used to mimic a 'IS-A' relationship between classes.Prefer composition to inheritance [1].
In the example below, there is a base class called Base, having a method to say hello. It has a derived class called Derived, having a method to say bye. The derived class inherits the method to say hello:
class Base { public: Base() {} void sayHello() const { std::cout << "Hello!" << std::endl; } }; class Derived : public Base { public: Derived() {} void sayBye() const { std::cout << "Bye!" << std::endl; } } int main(int argc, char* argv[]) { Base b; b.sayHello(); Derived d; d.sayHello(); //Inherited from Base d.sayBye(); return 0; }
- include <iostream>
Inheritance and function calls
In this code I show functions taking base and derived classes as an argument and I comment out the ones not possible. I also show when you can do an upcast or downcast. The first example uses plain pointers, the second smart pointers:Example #1 using plain pointers
//--------------------------------------------------------------------------- struct Base { Base(const int& value) : mValueBase(value) {} virtual void doCout() const { std::cout << "Base: " << mValueBase << std::endl; } const int mValueBase; }; //--------------------------------------------------------------------------- struct Derived : public Base { Derived(const int& value1, const int& value2) : Base(value1), mValueDerived(value2) {} virtual void doCout() const { std::cout << "Derived: " << mValueBase << " " << mValueDerived << std::endl; } const int mValueDerived; }; //--------------------------------------------------------------------------- void funcBase(const Base * base) { //Does nothing std::cout << "funcBase called for Base with value " << base->mValueBase << std::endl; base; } //--------------------------------------------------------------------------- void funcDerived(const Derived * derived) { //Does nothing std::cout << "funcDerived called for Derived with values " << derived->mValueBase << " and " << derived->mValueDerived << std::endl; derived; } //--------------------------------------------------------------------------- int main(int argc, char* argv[]) { const Base * base = new Base(0); const Derived * derived = new Derived(1,2); const Base * poly = new Derived(3,4); funcBase(base); funcBase(derived); //Works by upcast funcBase(poly); //Works by upcast //funcDerived(base); //Does not work: Cannot convert 'const Base *' to 'const Derived *' //funcDerived(dynamic_cast<const Derived*>(base)); //ERROR!!! Cannot upcast Base funcDerived(derived); //funcDerived(poly); //Does not work: Cannot convert 'const Base *' to 'const Derived *' funcDerived(dynamic_cast<const Derived*>(poly)); //Works after downcasting with dynamic cast delete base; delete derived; delete poly; return 0; }
- include <iostream>
Example #2 using smart pointers
Upcasting smart pointers is tough! downcasting is not possible (to the best of my knowledge), so I use a plain pointer:void funcBase(const boost::shared_ptr<Base> & base) { //Does nothing std::cout << "funcBase called for Base with value " << base->mValueBase << std::endl; base; } //--------------------------------------------------------------------------- void funcDerived(const boost::shared_ptr<Derived> & derived) { //Does nothing std::cout << "funcDerived for boost::shared_ptr called for Derived with values " << derived->mValueBase << " and " << derived->mValueDerived << std::endl; derived; } //--------------------------------------------------------------------------- void funcDerived(const Derived * derived) { //Does nothing std::cout << "funcDerived for plain pointer called for Derived with values " << derived->mValueBase << " and " << derived->mValueDerived << std::endl; derived; } //--------------------------------------------------------------------------- int main(int argc, char* argv[]) { boost::shared_ptr<Base> base(new Base(0)); boost::shared_ptr<Derived> derived(new Derived(1,2)); boost::shared_ptr<Base> poly(new Derived(3,4)); funcBase(base); funcBase(boost::shared_ptr<Base>(boost::weak_ptr<Base>(derived).lock())); funcBase(poly); //funcDerived(base); //[C++ Error] shared_ptr.hpp(162): E2034 Cannot convert 'Base * const' to 'Derived *' //funcDerived(dynamic_cast<Derived*>(base.get())); //ERROR!! Cannot downcast a Base class funcDerived(derived); //funcDerived(poly); //[C++ Error] shared_ptr.hpp(162): E2034 Cannot convert 'Base * const' to 'Derived *' funcDerived(dynamic_cast<Derived*>(poly.get())); //Possible downcast after obtaining the plain pointer return 0; }
- include <iostream>
- include <boost/weak_ptr.hpp>
- include <boost/shared_ptr.hpp>
- include <boost/intrusive_ptr.hpp>
Topic links
Code links
- argc
- argv
- boost
- boost::shared_ptr
- class
- cout
- endl
- int
- main
- public
- return
- shared_ptr
- std
- std::cout
- std::endl
Reference
1) Herb Sutter and Andrei Alexandrescu. C++ coding standards: 101 rules, guidelines, and best practices. ISBN: 0-32-111358-6. Chapter 34: 'Prefer composition to inheritance'.[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
