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
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).
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.
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.
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.
IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;
Related
#include<iostream>
using namespace std;
class Base
{
public:
void show() { cout<<" In Base \n"; }
};
class Derived: public Base
{
public:
void show() { cout<<"In Derived \n"; }
};
int main(void)
{
Base *bp = new Derived;
bp->show(); // RUN-TIME POLYMORPHISM
return 0;
}
In the above code, show() is declared in the base class and is overriden in the derived class. The base class pointer bp points to a derived class object. Now, when bp to call the non virtual show() function.
Output:
In Base
But, bp points to derived class, so why the base's function is called rather than the derived class function?
// RUN-TIME POLYMORPHISM
In C++ it's opt-in. For a function call to be resolved polymorphically at run-time, the programmer must explicitly say that's desired by marking it virtual.
The reason is that dynamic dispatch is never without a cost, and a staple of C++'s design is that "you don't pay for what you don't need". You must say you really need it for it to be enabled.
You need to make show() virtual to allow kicking in of runtime polymorphism.
virtual void show() { cout<<" In Base \n"; }
The core issue here is that show method is not overridden in the derived class. Starting with C++11 you can use override specifier to ensure that method really does override something so compiler will detect this problem for your:
class Derived: public Base
{
public:
void show() override { cout<<"In Derived \n"; }
};
prog.cc:13:10: error: 'void Derived::show()' marked 'override', but does not override
In order to override a method it should be declared as virtual in base class:
class Base
{
public: virtual
void show() { cout<<" In Base \n"; }
};
Most folks have already answered that you need to declare a function to be virtual for it to bind at runtime when your code executes.
I want to add that without virtual, the method to be called is decided at compile time and it will pick the method of the class whose variable/pointer type you declared. In your case, Base class type.
Additionally, would like to provide a good to read link which can help clear your concept of runtime polymorphism in C++ : https://www.geeksforgeeks.org/virtual-function-cpp/
To complement the other answers posted here, with reference to this comment:
I know, but base pointer point to derived then why call base function?
Please see this post: https://stackoverflow.com/a/50830338/5743288
It follows, therefore, that if you were to do this:
Derived *dp = new Derived;
dp->show();
You would get the following output:
In Derived
even without declaring show() as virtual (because the compiler would then know which method you have said that you want to call).
So, as others point out, if you want the service you have to pay the price (although, even with your original code, the compiler would probably be smart enough to optimise out the virtual function call anyway, see here).
This is actually what is call RUN TIME POLYMORPHISM. And in C++ its programmers discretion to call desired function of base or derived class, based on the object given to base class pointer.
Irrespective of the base class pointer pointing to any derived class object. If the function being called is non-virtual then always base class function will be called to a base class pointer.
To call derived class function from a base class pointer the function must be marked as virtual.
int main(void)
{
Base *bp = new Derived;
bp->show(); // RUN-TIME POLYMORPHISM
return 0;
}
compiler bind it with base class object while compiling
"new Derived" passing object to base but it been binded with base object it refer to same class
once if you add virtual binding will happen run time and once object passed by derived it bind with drived class
In c++,even-though you make the base class pointer point to derived class object, it still calls the function from the base class, this is because of Early binding, so in order to achieve Late binding make the function inside the base class as virtual.
i.e., virtual void show()
{
.......
}
Now, the o/p will be "In Derived".
I'd like to add the extra functionality without changing the existing class.
Say,
class base{
public:
int i;
base(){i = 1;}
virtual void do_work(){ /*Do some work*/ }
};
If I want to add serialization member function to it, I will simply create a derived class
class derived : public base{
public:
void serialize();
};
void derived::serialize(){
cout << "derived class" << endl;
}
And I do need to handle existing base objects,e.g.
int main(){
base a;
derived & b = static_cast<derived &>(a);
b.serialize();
}
This example runs without problems. But I do know the downcast through static_cast is something to be avoided in general.
But I'd like to know if the downcast for this particular use case can be considered safe since the derived class only has one extra member function. Will it has some potential undefined behavior for accessing vtable?
The way you're extending Base you're not making use of the vtable because you have no virtual methods. It may be easier to think of it as Derived has A Base; That you created a new class that contains a Base member variable.
My Suggestion.
Template Function
I personally would go with a template function. You can keep all the work in your original question, and avoid the need of adding virtual calls to your class.
template<typename T>
void serialize_object(T& t)
{
t.serialize()
}
And then based on your example.
Derivied d;
serialize_object(d);
The big benefit is that you're not adding runtime cast here. The compiler will inform you if you pass an object that doesn't have a method serialize.
Go Virtual
If you really want to handle this through a virtual interface do so.
struct Serializable{
virtual void serialize()=0;
virtual ~Serializable(){}
}
class Derived : public Serializable {
public:
void serialize() override;
}
void Derivied::serialize()
{
std::cout << "Yah\n";
}
Then in your code.
Derivied d;
Serializable& s = dynamic_cast<Serializable&>(d);
However, the big concern here is who is the owner of your base class? Did they provide a virtual dtor? If not, then making use of std::unique_ptr or std::shared_ptr could cause you to not deal directly with the interface.
If you can write the serialize function in a derived class without touching private or protected members then you should simply make it a free function. That solves everything.
You can't just cast a base class object to an inherited class. Any members in the inherited class will not have been created and initialized. You need to start with an object of the inherited class.
You can go the other way, of course, and call base class functions from a function of a class inherited from the base, because the base class object will always be there as part of the inherited class object, by definition.
If you have a pointer to the base class, and you build with RTTI, you can use dynamic_cast to cast to an inherited class, but that cast will fail and return NULL if the object is not of the class you're trying to cast to. But usually it's better to call a virtual function than to use dynamic_cast.
Does it make sense for a function to return a pointer to an abstract class?
Of course, that's the whole point of polymorphism : to pass around and use pointers to abstract classes, regardless of what the concrete implementation is.
Among others, the Factory Pattern typically returns a pointer to an abstract class.
Yes it makes sense to manipulate pointer (or reference) to an abstract class in order to decouple the interface from the actual implementation and exploit the benefits of polymorphism.
But note that if the function is in charge of allocating the returned object (some kind of factory), make sure to use a virtual destructor to be able to correctly delete the object from the abstract class pointer :
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {
public:
~Derived() override {
// Do some important cleanup
}
};
Base* factory() {
return new Derived;
}
Base* base = factory();
base->~Base(); // calls Derived::~Derived
Without the virtual destructor's of Base, the destructor of Derived would not have been called.
Yes it does make sense. It's like using interfaces.
Sort of. Say you have an abstract class named AClass, with a concrete implementation called CClass. You could return a pointer to an instance of CClass which could be of type AClass* or CClass*. However, as you can't instantiate an abstract class, you can't return a pointer to an instance of an abstract class.
However, if you return AClass*, your client will only be able to access the interface of AClass; if they want to access CClass functionality not included in the interface of AClass, they will need to cast the pointer to be CClass*.
I need help with a specific programming problem in C++ (not sure if this is even possible in C++). I need to be able to access all public member functions in Base class, but do not want to allocate memory for the Base class data while allocating the Derived class object.
Lets say, I have:
class Base
{
public:
Base();
~Base();
int GetFoo() { return foo; }
// other public member functions of Base class
private:
int foo;
// other data
};
class Derived : public Base
{
public:
Derived(Base *BasePtr);
Derived(Base &BaseRef);
~Derived();
double GetXyz() { return xyz; }
// other public member functions of Derived class
private:
double xyz;
// other data
};
Now, lets say I already have a Base class allocated and initialized. I want to create a new Derived class object by referring to that existing Base object and allocate memory only for the data specific to the Derived class. Following the above example, I would have already allocated memory for "int foo" in the Base class object and only want to allocate memory for "double xyz" in the Derived class object.
Base *basePtr = new Base();
Derived *derivedPtr = new Derived(basePtr); // what is the content of this function?
What should be the memory allocation or the constructor for the Derived class look-like? I want to inherit all data and member functions of the Base class, but without doing a "combined" data allocation of Base and Derived. I have tried overloading operator new but no luck. Any help is appreciated.
I'm not sure if it fits your requirements, but you could simply copy the contents of the Base stored in basePtr inside a new Derived object, then delete the Base object and point at the new Derived object with the old Base pointer. Like this:
Base *basePtr = new Base();
/* Do something with base here */
Derived *derivedPtr = new Derived(basePtr);
delete basePtr;
basePtr = derivedPtr;
derivedPtr = 0;
That way you'll end up with only one object (of type Derived) and won't have to store a separate pointer to it, nor store the Base object, and that seems like what you need.
Update:
in my case, I cannot delete the Base object since I would have created millions of them (using GigaBytes of RAM space) and people could be using pointers/references to those objects, so copying them to Derived objects and deleting the old Base objects doesn't work for me.
In that case, maybe you should try to do an "extendable* structural wrapper. First create an simple class without any method or member:
class Additional{};
Then create a wrapper structure:
struct wrapper{
Base *basePtr;
Additional *moreInfo;
}
Then, instead of deriving your Derived class from Base, derive it from Additional. And instead of storing milions of Base pointers, store milions of wrapper pointers. IT'll make your code a bit longer and harder to understand, but it'll do what you need. Well - unless the only thing your Derived class adds is a pointer or any data that takes less size.
If you've got virtual functions in Base, in order to use them with the new hierarchy, oyu'll just have to check every time:
wrapper *wrapperPtr = &alreadyCreatedSomewhereWrapper;
if(wrapperPtr->moreInfo)
wrapperPtr->moreInfo->function();
else
wrapperPtr->basePtr->function();
Use multiple inheritance.
class Base()
class Derive1() : Base
class Derive2() : Base
class MostDerive() : Derive1 , Derive2
MostDerived() will be thin. Derive1 and Derive2 will need to be deterministically constructed, but that can be imposed, or some Init() functions can be used.
class base
{
public:
virtual void showbase() {
// ----------
}
};
class base1 {
public:
virtual void showbase1() {
// -------
}
};
class derived : public base, public base1
{
void showbase() {
// ----
}
void showbase1() {
// -------
}
};
int main()
{
base* p = new derived();
p->showbase1();
base1* p1 = new derived();
p1->showbase();
}
As per my understanding about virtual function is that compiler deals it with run time (vtable mechanism), then why I am getting compile time error.
To simulate a compiler, consider what a compiler sees:
class base
{
public:
virtual void showbase() {
// ----------
}
};
base* p = /*blah blah*/;
p->showbase1();
Yes, base is a polymorphic class. And p is indeed a pointer-tobase. But since p points just to a base, and importantly not to a base1 (where showbase1 lives) the compiler interprets the above code like this. Obviously, I'm paraphrasing:
Here is a class named `base` with a single virtual method called `showbase`.
Here is a pointer to a `base` object. Call the method named `showbase1`
And the compiler complains:
Um, excuse me buddy, but base doesn't have a method called
showbase1.
You asked:
[My] understanding about virtual function is that compiler deals with
it at run time. Why I am getting compile time error?
Because the code you've written is nonsense. Here basically is how polymorphism works.
You define a base class with virtual methods.
You define a derived class that overrides those virtual methods.
The compiler creates a vtable which maps the names of the methods in the base class to the implementation in the derived class.
When you call a method in the base class through a pointer (or ref) to the base class, the derived class' implementation is called.
But what you are trying to do is:
Define a base class with virtual methods.
Define a derived class which overrides those virtual methods.
Call a function in a completely different class.
As per my understanding about virtual function is that compiler deals it with run time (vtable mechanism), then why I am getting compile time error.
"Deals with it" is pretty vague and vtables are not magic; In C++ virtual dispatch allows for the actual function called to be one that overrides the statically declared virtual function. That means that the function which is being overridden must be known at compile time.
The vtable does not contain information that would be necessary to look up functions at run-time. Instead, it's basically just a list of pointers to overriding functions. The base provides a complete list of its virtual functions and so, given a particular base type, the compiler knows at compile-time where to go in the vtable for that base for a particular function override; The compiler can generate code that goes directly to that spot in the vtable, gets the pointer, and calls the overriding function.
Then, at run-time, when the actual object of derived type is created, the derived object's constructor fills in the base's vtable, so that anything checking the vtable will get pointers to the derived type's functions.
So the problem with your code is that the function you're calling, showbase(), is not on the list of virtual functions for the type the compiler knows you're accessing, base1; The compiler can't know where in base1's vtable to get a pointer for a function override named showbase(), because there is no such entry in base1's vtable.
A base class pointer to a derived class can only access the member functions defined in the base class. It is illegal to try and access other functions defined in the derived class through it. In your case base class does not define showbase1 and therefore this is illegal
base* p = new derived();
p->showbase1(); //illegal
However, you can do this:
p->showbase(); // legal because showbase is a member function of base
Similarly you can't access showbase1 using a base class pointer
base1* p1 = new derived();
p1->showbase(); //illegal
p1->showbase1(); //legal
Your base class(es) only know about their own member functions, so you can't use it this way. You could do this instead:
base* p = new derived();
p->showbase();
base1* p1 = new derived();
p1->showbase1();
To answer your question about runtime polymorphism, it is dealing with runtime polymorphism (late binding) via the vtable, as you say. But with multiple inheritance, there is essentially a vtable for for each base class. You can't access one base class' vtable via a pointer to the other base class.
p'static type s type is base and hence you can only call with it functions that have been definied into base even if at the end, it will be the functions from derived which will be called because p's dynamic type is derived
Same thing happens for p1.
Maybe you meant p->showbase(); and p1->showbase1();