Reputation: 539
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?
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
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
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
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
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
Reputation: 1810
IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;
Upvotes: 0