Calling Inherited Class Specific Functions in C++ - c++

I have the following problem. I am busy coding up an inheritance structure in C++. Briefly, this is what I am attempting to do. Class A is the base class and classes B and C are inherited class. Classes B and C each have different and unique member functions.
Now, using the boost smart pointer library I make a vector of shared pointer of class type A as follows:
class A{
A();
virtual print();
}
class B : public A{
B();
virtual print();
}
class C{
C();
virtual print();
void uniqueFunc();
}
int main(){
vector<shared_ptr<A> > myA;
shared_ptr<B> myB;
shared_ptr<C> myC;
myA.push_back(myB);
myA.push_back(myC);
}
Now I have a method for checking the type of members within the vector. This isn't the issue. My question is, how do I call uniqueFunc for a member of class type C within the vector. Would I have to downcast? Or do I have to create virtual function. I do however, need uniqueFunc to be unique to class C. I would like to avoid creating copies of members and rather directly change the member in the vector.

You either need to downcast to boost::shared_ptr<C> or create a virtual function in A.
Assuming you want to downcast, you could use Boost's pointer cast functions:
boost::static_pointer_cast<C>(myA.back())->uniqueFunc();
(or use dynamic_pointer_cast<C> if you need dynamic type checking.)

Related

Accessing virtual class through the pointer

I have to design the specific architecture of the project. I got stuck while trying to create the pointer to the virtual class, and got Segmentation fault (seems my pointer was not assigned correctly).
Below I included the draft of what I'm trying to do.
// Class A has to be pure virtual. It will be inherited by many classes in my project.
class A:
{
public:
virtual void myFunction() = 0;
}
// Class B implements the method from the class A
#include <A.h>
class B: public A
{
public:
void myFunction(); // IS IMPLEMENTED HERE!!
}
// Class C creates a pointer to the class A.
#include <A.h>
class C:
{
A *ptr;
ptr->myFunction(); //Here I want to run myFuction() from the class B.
}
How can I make a connection between those three, so I get the result I want.
I can't change the architecture, or simply omit any of the classes A, B or C.
Thanks for help!
The virtual calls allow to access a function from an object through a pointer or reference of a base type. Note that the object itself needs to be of the type that implements the functionality.
So, in class C you can have something like:
B b;
A *ptr = &b;
ptr->myFunction()
or
A *ptr = new B();
ptr->myFunction()
Either way, you need to create an object of type B, and assign it to a pointer of type A*.

Extend the existing C++ class

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.

How can an pointer of superclass access variables of subclass?

I have a class A and class B which inherits from class A. Class B has a variable and a function that are not available in class A. I made a pointer
A* ptr=new B();
So how can ptr access the variable and function that belongs to class B?
Class A simply cannot "see" the functions of class B. Instead, you'd have to use something like a dynamic_cast from A to B, check for null, and then proceed as you like. Here is a nice tutorial to explain this a lot better than I can. Each of the casts have their advantages and disadvantages; learn them well. Also, try to avoid C style casting.
EDIT : Seems I misread the question. The answer is still correct, though. Class A would not be able to "see" the variables of Class B. The casting would still allow you access to them.
You can force the derived class to implement a pure virtual method defined in the base class:
class A
{
public:
virtual void do_things() = 0;
};
class B : public A
{
public:
virtual void do_things()
{
//Implementation
}
};
This way you can call the method implemented by class B through a pointer A*:
A* a_ptr = new B();
//The method implemented in class B will be called
a_ptr->do_things();
You could also make the assumption that a_ptr points to an object of class B. If a_ptr doesn't point to a B the pointer returned by dynamic_cast<B*> will be a nullptr. You can use static_cast<B*> if there are no virtual methods in A.
b_ptr = dynamic_cast<B*>(a_ptr);
b_ptr->do_things;
This way you don't need the pure virtual function in class A.

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
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;

Multiple Inheritance

#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
The above foo call is a compile time error.
I want to call foo with obj's B part without using virtual inheritance. How do i do that.
Also, in case of virtual inheritance, why the offset information need to be stored in the vtable. This can be determined at the compile time itself. In the above case, if we pass foo with D's object, at compile time only we can calculate the offset of D's A part.
Inheriting twice
With double inheritance you have an ambiguity - the compiler cannot know which of the two A bases do you want to use. If you want to have two A bases (sometimes you may want to do this), you may select between them by casting to B or C. The most appropriate from default casts here is the static_cast (as the weakest available), however it is not realy needed (it is still stronger than your case needs), as you are not casting to a derived type. A custom safe_cast template should do the job:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
Compile time types - use templates
Also, in case of virtual inheritance,
why the offset information need to be
stored in the vtable. This can be
determined at the compile time itself.
In the above case, if we pass foo with
D's object, at compile time only we
can calculate the offset of D's A
part.
This is a misconception. The foo function as it is written now has no compile type information about ptr type other than it is A *, even if you pass B * or C*. If you want foo to be able to act based on the type passed compile time, you need to use templates:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
Virtual Inheritance
Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify so:
class B: public virtual A ...
class C: public virtual A ...
With this the code would compile, but with this solution there is no way you could select between B::A or C::A (there is only one A), therefore this is probably not what you are about.
Virtual functions
Furthermore, your questions seems to be confusing two different concepts, virtual inheritance (which means sharing one base class between two intermediate base classes) and virtual functions (which mean allowing derived class function to be called via base class pointer). If you want the B::eat to be called using A pointer, you can do this without virtual inheritance (actually virtual inheritance would prevent you doing so, as explained above), using virtual functions:
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
If virtual functions are not acceptable for you, the compile time mechanism for this are templates, as explained above.
Use a cast - static_cast is required here to cast up the heirarchy.
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
First of all, obj does not have a member named B. It Inherits from B, which means that it inherits all of B's members as its own.
You can call:
foo(static_cast<B*>(&obj)); to make it work.
I don't think the static_cast will work.
When you are on the foo function, all the compiler knows is that you have a pointer to A, whatever the type you passed as parameter.
If you don't use virtual inheritance, then I think there is no way to call a B function from a pointer to A.