I have a key-value container class that holds pointers to heap-allocated objects of a base type. The insert method of the container instantiates one of 2 derived class objects (based on a runtime flag) and inserts it into itself.
I have a Find method with the following signature:
bool Find(int key, Base *&result);
The classes that use of this container know which derived class is actually being stored, because there is a one-to-one mapping between a user of the class and one of the derived types.
So when a user tries to call the Find method as follows:
DerivedA *a = nullptr;
bool found = container.Find(10, a);
I get a compiler error saying that there is no matching function.
So it seems that implicit conversion isn't happening between the base and derived classes. I suspect it has to do with the fact that I'm passing the pointer by reference, but I'm not sure.
What is the "correct" way to achieve what I'm after here?
Thanks!
I suspect it has to do with the fact that I'm passing the pointer by reference
Imagine that Find updates the passed pointer and now it points at a new instance of Base. But the caller still interprets it as a pointer to DerivedA.
Basically the issue is that you can assign
Base* basePtr = &derived;
but not the way around. So if the only guarantee of your Find method is that it finds an instance of Base type, we cannot just assign the pointer to it to DerivedA.
If you do know that your Base class pointer points at DerivedA, you could consider dynamic_cast:
Base* Find(int key);
....
DerivedA* a = dynamic_cast<DerivedA*>(Find(key));
(Returning the pointer might be better, as #juanchopanza comment suggests.)
Add an overload of Find
Base *pi=result;
bool r=Find(key,pi);
result=dynamic_cast<DerivedA *>(pi);
return r;
Related
I recently learned about upcasting and downcasting in C++. However I came up with a few questions during reading about downcasting. Say I have two classes
class Base {
public:
virtual void foo() {}
};
class Derived : public Base {
public:
Derived(int i) {
mem = i;
}
int mem;
};
My questions are the followings:
If I create an object Derived d(1), upcast to Base class, and then downcast it back to Derived class, is 'mem==1' preserved? Do I still have access to it? Assume pointer or reference is used so object slicing doesn't happen and dynamic_cast is used for downcasting.
When downcasting from Base class to Derived class, there will an additional member variable 'mem'. Is memory allocated for 'mem' during run-time (using dynamic_cast)? To what value will it be initialized to?
After some simple experiments, 1 seems to be true.
However for 2 it seems I can't start from a Base class pointer and dynamic_cast it into Derived class pointer as dynamic_cast returns null.
I read from another post saying "But the basic point of dynamic_cast is that it first checks that the pointee object is really of the derived type, and then returns a pointer to it, or returns a null pointer if the pointee object isn't actually of (or derived from) the requested target type."
Is this saying we can't actually start from the Base class and simply downcast it into Derived class, but rather the whole point of dynamic_cast is to "cast back" something that has been upcasted?
It depends; if you cast a Derived object to Base, the result is a new object created by omitting the fields that are not in the Base. However, if you cast a pointer to Derived (i.e. Derived*), the result is a pointer which points to the same object but whose type is Base*.
It depends; if you cast a Base object, you get a compile error unless you overload the typecast operator for doing such an operation (you have correctly observed that the values of the fields would otherwise be undefined). However, if you cast a Base* (a pointer) to Derived* (using dynamic_cast<Derived*>(p)), the result depends on the object the pointer points to. If it points to an instance of the Derived class (or its subclass), the result is a Derived* pointer to that object; otherwise, you get a nullptr pointer of type Derived*.
I have got problem with passing inherited class type as argument to method that takes its base class type.
class Base {...}
class Derived : public Base {...}
class Container {
vector<Base*> cont; //1
public:
void addToCont(Base x) { //2
cont.push_back(&x);
}
}
int main() {
Container c;
c.addToCont(Derived(p1,p2)); //3
}
1) I suppose I need to have container of pointers to objects to keep it working
2) Here is error in conversion from Derived to Base
3) I am not supposed to change this call. I tried
Derived d(p1,p2);
c.addToCont(d);
with
addToCont(Base& x)
and it worked for me.
My problem is that I've got 3 derived classes and I don't want to overload the add method 3 times. I guess I will have to add some virtual method or some type-casting to those classes, but I couldn't find anything about that. I am novice in inheritance and quite confused of this. Thanks for all your help.
Some notes:
Must use a vector of pointers to the Base, so that you can handle objects from the hierarchy. Goes without saying that you're probably better off with using some kind of smart pointer instead of raw pointers, but that goes in preferences and how much you love risk.
Using void addToCont(Base x) is wrong because even if you were only adding a Base object, you will be adding a pointer to a local variable (the pass-by-value parameter)
Using void addToCont(Base &x) the way you do it with a local Derived d is wrong too, for the same reasons as before, as soon as d goes out of scope, you're left with a dangling pointer stored in the pointer
Calling addToCont(Derived(...)) passes a temporary object. That must be taken into account when you think about your memory management.
Not sure why you see a need for overloading addToCont for all Derived classes, that's not what you did on void addToCont(Base &x)
The solution (if you keep to the raw pointers) is to do void addToCont(Base *x) there you can pass a pointer to Base or to any Derived. Again, you must be mindful about the memory management. You're Derived object probably needs to be allocated with a new Derived(...) and you must watch about who owns it, and who has responsibility for deleting it (for example, when the Container object is destroyed).
You probably should remember to make virtual the destructor of Base, because you will be destroying Derived objects from Base pointers, and if the destructor is not virtual, the object will only be partially destroyed.
If addToCont(Derived(...)) call is absolutely required, then you might want to consider to use the void addToCont(Base &x) defininition.... but them, you must clone the object before inserting it into the vector:
void addToCont(const Base &x) { //2
cont.push_back(x.clone());
}
But then.. you need a virtual Base *clone() const method to be implemented (at least) in the Derived classes, that will produce a Base pointer with an exact copy of the Derived object, involving extra copies of the objects and extra cloning...
Derived classes are only "possible to use" when they are either references or pointers. If you convert a class to a base-class without a reference or pointer, you won't be able to use it as a derived class later.
If you are actually storing pointers in your container, then I would make it explicit, so:
class Container {
vector<Base*> cont;
public:
void addToCont(Base* x) {
cont.push_back(x);
}
~Container()
{
for(auto a : cont)
{
delete a;
}
}
}
And in main:
Container c;
c.addToCont(new Derived(p1,p2));
Note that in your original code, the Derived(p1, p2) will get destroyed again just after call to addToCont(...), so your array would be pointing to a "dead" element of the Derived class. Which was probably not what you actually wanted (since it's undefined behaviour to ever use that element, and building up a container full of useless elements is pretty pointless)
Let's say I have class SuperClass { public: int a; } and class SubClass : SuperClass { public: int b; } and I took a pointer to an instance of the SubClass SubClass *subPointer and addressed that pointer to a SuperClass pointer SuperClass *superPointer = subPointer. Now of course I can always cast the superPointer object to a pointer of SubClass because the only thing it stores is an adress. But how would I know if the object superPointer is pointing to an instance of SubClass or is just a SuperClass pointer?
You usually don't want to use typeid for this.
You usually want to use dynamic_cast instead:
if (SubClass *p = dynamic_cast<SubClass *>(SuperClassPtr))
// If we get here (the `if` succeeds) it was pointing to an object of
// the derived class and `p` is now pointing at that derived object.
A couple of notes though. First of all, you need at least one virtual function in the base class for this to work (but if it doesn't have a virtual function, why are you inheriting from it?)
Second, wanting this very often tends to indicate design problems with the code. In most cases, you want to define a virtual function in the base class, which you (if necessary) override in the derived class to do whatever's needed so you can just use a pointer to the base class throughout.
Finally, as it stands right now, most of the conversions will fail -- you've used the default (private) inheritance, which prevents the implicit conversion from derived * to base * that you'd normally expect to see happen (you probably want class SubClass : public SuperClass).
Use RTTI machanism. Like:
if(typeid(*superPointer) == typeid(SuperClass)) superPointer->dosomething();
if(typeid(*superPointer) == typeid(SubClass)) superPointer->dosomethingelse();
I'm trying to create the constructor of a nested class, which inherits from a parent nested class, using its constructor. Basically:
DerivedList<T>::DerivedNested::DerivedNested(DerivedNode*& ptr)
: BaseList<T>::BaseNested::BaseNested(ptr)
{}
The prototype of the constructor of my BaseNested goes like this:
BaseList<T>::BaseNested::BaseNested(BaseNode*& ptr)
(and is required to get the ptr parameter by reference since it needs the address of said pointer in its code)
I figured I had to cast my DerivedNode* to a BaseNode*, but : a static_cast::BaseNode*>(ptr) finds no matching functions since it isn't a reference, and a static_cast::BaseNode*&>(ptr) gives an invalid cast error.
The same goes for dynamic_cast. A reinterpret_cast compiles, but gives something incorrect during excecution.
Does anyone know how I could call that parent constructor?
If you think you need a reference, that's probably because you want to modify the pointer later. The problem is that the type of the pointer in the derived class is DerivedNode*, and BaseNode* in the base class. What if the base class affects a DerivedNode2* to its pointer ?
You should use setters, or move the logic from the base class to the derived ones.
I have an object of a base class which is actually pointing to a derived class like this
Base *b = new Derived()
What I want to know, is it possible to pass the base class pointer by reference to some function which can cast the object back to Derived class. Something like this
Dummy_cast_fn(&b) // casts b to derived class
After calling Dummy_cast_fn, b should have a full copy of Derived class (no slicing).
Edit
I dont understand the part that there is no slicing since pointers are used. My problem is Derived class is returned from a function call to a shared library and I do not have access to .h file for the Derived. Only information I have is that Derived is based on Base class. I have access to Base.h so I can instantiate an object of Base but problem comes when I try to access the functions which are defined in Derived but not in Base. So I was wondering if I can typecast the Base to Derived type, then I will be able to access the function defined in Derived and not in Base.
As long as b is a pointer or reference to a Derived, you can always:
Down cast it to a Derived.
Treat it as a Base as long as you're using b.
Namely, what determines what you can do with b is its static type, in this case Base. However, since it actually points on a Derived, you can always downcast it. Yet, to use it as a Derived you must have a variable whose type is Derived as well.
So, if the purpose of Dummy_cast_fn is just to fix something in b - it's useless. If an object is sliced, nothing can fix it. But in your case, there's no slicing, since you're using pointers.
Edit according to the question's edit:
First, you're Derived object is not sliced. Let's get that off the table. You have a pointer to a complete Derived (assuming that's what you've been passed), but you only have access to its Base part when using the Base pointer. Now, you say you don't have the definition of Derived. This means you won't be able to downcast to that type, because the compiler doesn't know how it's defined. No casting will work here. There's no legal C++ way you can call that sum function if you don't have Derived's definition.
I do wonder why the author of Derived provided you its documentation without providing its definition. With this kind of polymorphism, the provider usually lets the user have some "interface", leaving the actual type as an internal implementation detail. If you can't use Derived because you don't have its definition, there's no point in letting you have its documentation.
You cannot change a Base* into a Derived*, but you can get a Derived* pointing to the object that a Base* is pointing to, using dynamic_cast:
Derived* d = dynamic_cast<Derived*>(b);
if (d) {
// cast was succesful
} else {
// cast failed,
// e.g. because b* does not point to a Derived* but some other derived type
}
You can't change the type of your Base* b, you can however create a new pointer
Derived* p = static_cast<Derived*>(b);
and use that. Once b is declared as Base* you can't modify its type. You can also use dynamic_cast also although this is slower and may not strictly be necessary (although I cannot say for certain - that depends on your requirements). And if you are correctly using virtual functions you may not even need to do any casting at all - that is one of the purposes of polymorphism