I'm having real trouble to figure out this casting problem. Starting with 3 classes:
#include <vector>
// Pure virtual class
class Base1{
public:
virtual ~Base1();
virtual void do_sth()=0;
}
class Base2{
public:
int prop=3;
~Base2();
}
class Derived: public Base1, Base2{
~Derived();
void do_sth(){print("Hi");};
}
How can I perform the following conversion?
std::vector<Base1*> vec1
vec1.reserve(10);
for( int i = 0; i < 10; ++i )
vec1.push_back(new Derived());
// To this type...?
std::vector<Base2*> vec2 = ?????;
Some remarks:
I'd use dynamic_cast to perform safe casting from Base1 to Derived.
Ideally, no object copies are made in the process!.
My best bet so far is to call vec2.data() to obtain a Base1* pointer, then dynamic_cast to Derived, then static cast to Base2, but I don't know how to transfer memory ownership nor how to pass vector size.
The comments to the question have gotten rather muddled, so I'll post this partial answer here, rather than trying to straighten out the comments.
Base1 has a virtual function. Good start.
Derived is derived from Base1.
Derived is also derived from Base2.
If you have an object of type Derived you can create a pointer to Base1 that points at the derived object:
Derived d;
Base1* b1 = &d;
Now that you have a pointer to a polymorphic base class, you can use dynamic_cast to perform a cross-cast:
Base2* b2 = dynamic_cast<Base2*>(b1);
The compiler knows how to do that, and the result should be the same pointer value as you'd have gotten if you did it directly:
Base2* b2x = &d;
assert(b2x == b2);
Note, too, that since the code traffics in vectors of pointers, it seems that the Derived objects are being created with new Derived. If that's the case, and eventually the code deletes the Derived object through a pointer to one of the base types, then the base type must have a virtual destructor.
There are no Derived objects in vec1 nor vec2, so you can't get pointers to other base subobjects of a Derived from an element of either.
If pass a Derived to vec1.push_back, it will copy-construct a Base1 from the Base1 subobject of the Derived. This is called object slicing.
If you have a vector of pointers (raw or smart) to Base1 in vec1, then those could point to the Base1 base subobject of a Derived, at which point you can dynamic_cast<Base2*> them, which will in general give you a different pointer value.
Related
Quoting Effective C++, Scott Meyer, 3rd Edition , Item 27
class Base { ... };
class Derived: public Base { ... };
Derived d;
Base *pb = &d; // implicitly convert Derived* ⇒ Base*
Here we’re just creating a base class pointer to a derived class
object,
but sometimes, the two pointer values will not be the same. When that’s the case, an offset is applied at runtime to the Derived*
pointer to get the correct Base* pointer value.
Why are the two pointer values not the same? If it is because how the child and parent objects are laid out in the memory, then how does downcast work later?
This always happen when using multiple inheritance.
class Base1 { int a; };
class Base2 { double b };
class Derived : public Base1, public Base2 { ... };
Derived d;
Base1* pb1 = &d;
Base2* pb2 = &d;
Now &d cannot possibly be equal to both pb1 and pb2, because otherwise pb1 would equal pb2, which is not possible, because two different non-empty objects of unrelated types must occupy different regions of memory. So in at least one case a non-zero offset must be applied.
In most implementations with single inheritance the offset is zero, but the standard does not mandate that.
Indeed, a typical implementation would simply lay out the base object at the beginning of the derived object:
++-----++
||Base ||
|+-----+|
|Derived|
+-------+
But when there are more than one base, only one can go at the beginning:
++-----++
||Base1||
|+-----+|
||Base2||
|+-----+|
|Derived|
+-------+
The downcast works because the offset is fixed and known at compile time, so there's no problem to apply it when either upcasting or downcasting.
An exception to this is virtual inheritance. For a virtual base the offset is not known at compile time. Typically, the derived object contains an internal hidden pointer to its virtual base, so the upcast can work. But the base doesn't know where its derived object is, so the downcast cannot work, and is not allowed by the language.
When you have a single inheritance tree that is polymorphic, compilers require each object to begin with a VMT (virtual method table). If base class is polymorphic, the pointer values would match. But ff your base class is non-polymorphic and your derived class is polymorphic, the base class does not introduce the VMT, it is introduced by the very first polymorphic class down the tree. The VMT would be inserted before the base. Now the pointer values will not match.
class Base { virtual void dummy() {} };
class Derived: public Base { // no new elements added }
I like to know that
base *bptr;
derived *dptr;
bptr=new base;
dptr=dynamic_cast<derived*>(bptr); // this is not working ,dptr is NULL
dynamic_cast can also downcast (convert from pointer-to-base to pointer-to-derived) polymorphic classes (those with virtual members) if -and only if- the pointed object is a valid complete object of the target type"
here the pointed object is base object and is same as target object.
so here "complete" means some other meaning
thanks
dynamic_cast will only succeed if the dynamic type of the object matches the type you're casting to. Here
bptr=new base;
points to a base, not a derived, so dynamic_cast<derived*> will fail; there is no derived object it could point to. derived is a different type to base, even if it doesn't declare any members beyond those in the base class.
Try
bptr=new derived;
and the cast should succeed.
class Base
{
bool a;
};
class Derived : public Base
{
bool b;
};
void main()
{
std::shared_ptr<Base> base(new Derived());
}
So in this example the raw pointer of shared_ptr will point to an instance of Base, NOT Derived. Which I do not understand.
class Base
{
virtual void foo() {}
bool a;
};
class Derived : public Base
{
virtual void foo() {}
bool b;
};
void main()
{
std::shared_ptr<Base> base(new Derived());
}
But in this case the raw pointer of shared_ptr does point to Derived? I'm sure I'm missing something. can someone explain to me why this is happening?
In the first example, the classes do not have a virtual table, since there are no virtual functions.
This means, that since the shared_ptr expects a static type of Base, it will store a Base.
The second case also stores a Base, but the existence of a virtual table allows you to see that the dynamic type of the object is Derived.
First, the use of std::shared_ptr here is a red herring. In
this case, both std::shared_ptr and a raw pointer behave
exactly the same. In both cases, the expression new Derived()
returns a Derived* which points to the entire object. And in
both cases, using it to initialize a pointer to Base, be it
a raw pointer or any reasonably designed smart pointer will
cause the Derived* to be converted to a Base*, which points
to the Base sub-object in the Derived. The Derived object
still exists, however, and can be accessed in several different
ways: via virtual functions, by using std::dynamic_cast if
Base is polymorphic (has at least one virtual function), by
using std::static_cast if you're 100% sure that the pointed to
object actually is a Derived, and probably some others I've
not thought of. In your first case, only the last is possible,
since in the first, Base is not polymorphic. In both of your
examples, however, the pointer points to a Base, which is
a subobject of a larger Derived.
There are some differences between std::shared_ptr and a raw
pointer. For example, in your first example, replacing
std::shared_ptr<Base> with Base* and manually deleting
through the pointer will result in undefined behavior;
std::shared_ptr has extra complications to avoid this. (But
the complications aren't without their drawbacks. Give Base
a virtual destructor, as it should have, and then make the
destructor of Derived private, for whatever strange reason,
and your first example won't compile.)
Assuming that I'm not using multiple inheritance or virtual inheritance, does the C++ standard guarantee that if I convert a Derived* to a Base* that both pointers will have exactly the same value? For instance, will the following code always call success(), even if Derived and/or Base have virtual functions?
Derived* d = new Derived;
Base* b = d;
if (((void*)b) == ((void*)d))
success();
else
failure();
If the base class has no virtual functions and the derived class does, the pointers would likely be different because the base class wouldn't have the vtable pointer present in the D object.
A Base Class pointer can point to a derived class object. Why is the vice-versa not true without casting?
Logically a base class would not have enough information of the derived class but a derived class should have the information of the base class as well.
I am missing some basics here.
If I tell you I have a dog, you can safely assume that I have a pet.
If I tell you I have a pet, you don't know if that animal is a dog, it could be a cat or maybe even a giraffe. Without knowing some extra information you can't safely assume I have a dog.
similarly a derived object is a base class object (as it's a sub class), so it can be pointed to by a base class pointer. However, a base class object is not a derived class object so it can't be assigned to a derived class pointer.
(The creaking you will now hear is the analogy stretching)
Suppose you now want to buy me a gift for my pet.
In the first scenario you know it is a dog, you can buy me a leash, everyone is happy.
In the second scenario I haven't told you what my pet is so if you are going to buy me a gift anyway you need to know information I haven't told you (or just guess), you buy me a leash, if it turns out I really did have a dog everyone is happy.
However if I actually had a cat then we now know you made a bad assumption (cast) and have an unhappy cat on a leash (runtime error).
We have two objects.
class A {
int a;
};
class B : A {
int b;
};
Allocate an instance of B. We can interface with that as either an A* or a B*.
Allocate an instance of A. If we were to cast it to a B*, should there be space allocated for the member b?
Uh, because the base class is not a derived class.
When you have a valid pointer to a type, then you are saying that the object pointed to will have certain data in certain locations so that we can find it. If you have a pointer to a derived object, then you are guaranteeing that the pointed-to object contains all of Derived's data members- but when you point to a Base, then it infact doesn't have that and Bad Things Happen™.
However, Derived is guaranteed to have all of the Base data members in the same locations. That's why a pointer to Base can actually point to Derived.
Because a derived class includes everything that is in the base class. But a base class does not include everything that is in the derived class.
Type casting a base class to a derived class is not recommended: What happens if you try to access members that are not part of the base class?
This is valid, because a tiger is an animal:
Animal * pAnimal = new Tiger();
This is not valid, because it is not true that the object is a poison dart frog.
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
The short answer
class A{
public:
method1();
};
class B: public A{
public:
method2();
};
int main(){
// Case 1
A* ptr_base = new B();
// Here I can call all the methods in A by ptr_base even though it is assigned B ...
// ... because B is derived from A and has all the information about methods of A
// Case 2
B* ptr_derived = new A(); // this will cause error
// Now here ptr_derived is assigned information of A ...
// ... So with this information can I call (*ptr_derived).method2(); ?...
// ... the answer is No because A does not have information of method2() ...;
// ... thus this declaration loses its meaning and hence error.
return 0;
}
Because C++ is a statically typed language, and allowing implicit Base-to-Derived conversions would break the type system. Bjarne Stroustrup did not want any "message not understood" runtime errors.
class Base
{
public:
int a;
}
class Derived : public Base
{
public:
float b;
}
Base * pBase = new Base();
pBase->a = 7; // setting the value of a in the base
// make a pDerived that points to the SAME DATA as pBase
Derived * pDerived = pBase;
pDerived->a = 5; // this would be okay, base has a public member 'a'
pDerived->b = 0.2f; // error pBase has no data member b and pDerived
// points to the SAME DATA as pBase
This is because, "the type of a pointer is the type of object the pointer points to". So,
If we have base type pointer (*B):
then we expect a base type object (and would like to access its functionalities) at the address pointed by B, and if we get a derived type object at that address then also we are able to access the required functionalities. This is because derived type is-a base type.
If we have derived type pointer (*D):
then we expect a derived type object at the address pointed by D and if we get base type object there then we will not be able to access derived class info from the base type object since base type is-not-a derived type.
Actions speak more than words.
Child too can have Parent Class object.
if you understand pointers well, limitations are off to you
In below code have printed both values by child class pointer ( which was having Parent class object).
Also proved that by printing their address.
Any suggestions are welcome!
#include<iostream>
using namespace std;
class Baap{
public:
int a;
void hoo(){ cout<<"hoo\n"; cout<<a;}
};
class Beta:public Baap{
public:
int a;
int b;
void hee(){ cout<<"hee\n"; }
};
int main(){
Baap baap;
baap.a=1;
Beta *beta=(Beta*)&baap;
baap.a=3;
beta->hee();
beta->hoo();
cout<<"\n beta = "<<beta<<"\n&baap = "<<&baap;
return 0;
}
//output
hee
hoo
3
beta = 0x7ffd11dd3834
&baap = 0x7ffd11dd3834
Because a base class pointer can point to an instance of the base class or any derived type. A derived pointer can only point to that derived type or any subclass of it.
struct Base {};
struct Derived : Base {};
struct Derived2 : Base {};
Base* p = new Derived(); //Fine, Derived inherits from Base
Derived* d = new Base(); //Not fine, Base is not an instance of nor derived from Derived.
Derived* d2 = new Derived2(); // Also not fine, Derived2 derives from Base, but is not related to Derived.
As far as the why goes: In general the base pointer is more general than the derived pointer. As such it knows less about the inherited type. A derived pointer cannot be assigned a pointer to a base type without casting simply because it cannot tell if the base pointer is of the Derived type or one of its children.
If assign an address from a base class pointer into a derived class pointer, you can potentially assign a base class object to a derived class pointer. You run the risk of accessing derived class members when you don't have a derived class. Whereas derived class methods would work on a base class, they would only do so if the method didn't access derived class member data.
That's a huge risk.
So we force you to cast so that you have to acknowledge the disclaimer that says (you may make a stupid mistake, please be careful).
In general , a pointer of one type cannot point to an object of a different type. However, there is an important exception to this rule that relates only to derived classes.
In this situation a pointer of type BASE* may point to an object of type Derived, i.e a base class pointer can point to a derived class object but vice versa is not true as the base object is not it's sub class object.