Koen Demonie
Koen Demonie

Reputation: 539

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

Upvotes: 2

Views: 69

Answers (5)

David Haim
David Haim

Reputation: 26476

the first and most major of your problem is that your thinking in Java. the words "interface" and "extending" are very Java oriented. C++ does not think this way.

for example, when someone talks about an "interface" in a C++ context, I may think he talks about the class decleration inside the .h file (as opposed to the implementation which lies in the .cpp file)

IDoable is a CLASS. period. the only difference is that it has a pure virtual functions that prohibits instansiation. other than that it behaves as a class, it can be inherited from, can hold member variables and anything else.

you just need to make sure the abstract function is overriden in some derived class in order for that class to produce objects.

thus said :

//in the stack:
Base base;
ExtendingBase eBase;
base.do();
eBase.do()

//in the heap with IDoable as pointer:
IDoable * base = new Base();
IDoable * ebase = new ExtendingBase ();
base->do();
ebase->do();

now, you may ask - how do I activate Base and ExtendingBase functions? so just like Java, you need to cast the pointer and only then call the right function.

 Base* realBase = (Base*)base;
realbase->someBaseFunction();

as many things in C++, this code is a bit dangerous. you can use dynamic_cast instead.

and one last thing - do is a keyword in C++, it cannot declare a function name.

Upvotes: 1

Marco A.
Marco A.

Reputation: 43662

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

Upvotes: 1

Lawrence Aiello
Lawrence Aiello

Reputation: 4638

You will have to implement your do() function in Base, since the function in the class IDoable is pure virtual.

If you decide to create an ExtendingBase object, the do() function will behave as it's implemented in Base, unless you override it by re-implementing it in ExtendingBase.

Upvotes: 1

Barry
Barry

Reputation: 302817

if I want to make a list of IDoable objects

You cannot make an IDoable object period. It's an abstract class, it cannot be constructed directly, so you cannot have a container of them. What you can do and what you likely intend is to have a container of IDoable*:

std::vector<IDoable*> objects;
objects.push_back(new Base);
objects.push_back(new ExtendedBase);

Or to express ownership better in C++11:

std::vector<std::unique_ptr<IDoable>> objects;

Given your interface, you can already call do() on any of these objects and that will do the right thing via virtual dispatch. There is one member function you definitely want to add to your interface though:

class IDoable {
public:
    virtual ~IDoable() = default; // this one
    virtual void do() = 0;
};

That way, when you delete an IDoable*, you will delete the full object, not just the base interface.

Upvotes: 1

Steve
Steve

Reputation: 1810

IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;

Upvotes: 0

Related Questions