Search code examples
c++inheritanceextending

inheritance of an implemented class


This is probably a simple question, please bear with me since I'm used to Java...

Lets say we have an interface:

class IDoable {
    virtual void do() = 0;
};

Another class:

class Base : public IDoable {
    //...
    virtual void do() { ... }
};

And a last class extending our base class:

class ExtendingBase : public Base {
    // some extra functionality
};

I am lost at the part if I want to make a list of IDoable objects, which can be Base objects or ExtendingBase objects. Do I have to add some method declaration of the methods in the Base class? How does this aspect work?

EDIT:

I have someList of type IDoable pointers and if I then try to add a Base object to that list I get the error:

IDoable is an ambiguous base of Base

Same if i try to add an ExtendingBase object

IDoable is an ambiguous base of ExtendingBase


Solution

  • Since do is a pure virtual method, it will have to be implemented in a derived class. You can't have a vector or array of IDoable objects because you can't instantiate such an object. You can have a vector or array of pointers or references to objects though.

    If you create an ExtendingBase object and call the do function, it will call the Base class' one (since ExtendingBase inherits that method).

    Virtual polymorphism enters into play when you call the do() function from a base class pointer or reference: the do() function appropriate to the dynamic type of the object pointed or referenced to will be called:

    class IDoable{
    public:
      virtual void dof()=0;
      virtual ~IDoable() = default;
    };
    
    
    class Base:public IDoable{
    public:
    virtual void dof(){std::cout << "Base";}
    virtual ~Base() = default;
    };
    
    class ExtendingBase:public Base{
     public:
      virtual void dof() { std::cout << "ExtendingBase"; }
    };
    
    int main()
    {
        IDoable *ptr = new Base(); // A smart pointer would be a better choice
                                   // but for clarity's sake I'm using bare
                                   // memory allocations here
        ptr->dof(); // Walks the virtual table and calls "Base"
        delete ptr;
    
        ptr = new ExtendingBase();
        ptr->dof(); // Walks the virtual table and calls "ExtendingBase"
        delete ptr;
    }
    

    Also notice the use of virtual destructors: they work like normal virtual functions and thus when calling delete on a base pointer, in order to actually destruct the right type of object (i.e. to call the right destructor in the hierarchy), you will need to make it virtual.

    As a sidenote: do is a reserved keyword in C++


    In response to your edit: if you have a vector or a list of IDoable pointers, you can't just add a derived object to it, but you should add a pointer to a derived object. I.e. the following is wrong:

    std::vector<IDoable*> vec;
    vec.push_back(Base());
    

    plus a base class remains a class (there is no interface concept in C++ as in Java) and you shouldn't inherit from a base class multiple times:

    class Base:public IDoable{
    ...
    class ExtendingBase:public Base, public IDoable <- nope
    ...
    

    that would only cause issues in identifying the base subobject. I recommend to read about the dreaded diamond problem in C++ (it's a way to solve a base class appearing multiple times in the inheritance hierarchy.. anyway a good design might probably avoid this in the first place).