Consider the following code:
class Base {
//some code
};
class A : public virtual Base{
//some code
};
class B : public virtual Base{
//some code
};
class C: public A, public B {
//some code
};
In other words we have multiple inheritance and all classes inherit from class Base. Now consider that the "this" pointer exists in code in classes A,B,C,Base. I know that in general we cannot assume that the "this" pointer value will be identical in all cases. But what it the "this" pointer is cast to the Base* class inside A,B,C whenever it is used. Is it correct to say that the casted pointer "this" after casting to the common Base* class will contain the same address inside A,B,C? Thanks
Yes. The virtual inheritance means that there is only one base class subobject of type Base, which is simultaneously a subobject of the C and the A and the B. A conversion (implicit or by cast) from pointer to any of those types to Base*, or initializing a reference Base& from lvalue of any of those types will cause the compiler to do the correct logic to find that single Base subobject.
But what it the "this" pointer is cast to the Base* class inside A,B,C whenever it is used
Note that there isn't even a need to cast (i.e. convert explicitly). A pointer to derived converts to base pointer implicitly.
Is it correct to say that the casted pointer "this" after casting to the common Base* class will contain the same value inside A,B,C?
A pointer doesn't "contain values" other than the value of the address of an object. The object whose address is stored is the pointed object. A pointer to a base points to the base sub object.
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*.
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.
Can any explain why baseclass pointer cannot be assigned to derived class pointer? I know it is not possible ,but i like to know the reason .logically derived class contain base class.Let me know the reason
Thanks in advance
Consider:
struct A
{
};
struct B : A
{
int b;
};
struct c : A
{
char c;
};
C cobj;
A* aptr = &cobj;
B* bptr = aptr; // Assuming this were allowed...
bptr->b = 10;
By doing that you'd have used memory beyond what is valid. You have created an object of size sizeof(C) but not you are treating it like it is of size sizeof(B).
A derived class can have its own data members and member functions in addition to all of those within the base class.
If you point the derived class pointer to the same thing as a base class pointer, the derived class pointer will think it's pointing to a derived class object, even though it's pointing to a base class object.
If you try to access derived class data members or member functions using this derived class pointer, it won't work because it's pointing to a base class object that doesn't have these capabilities.
For instance, let's assume I have a base class called Person and a derived class called Programmer. I can make a Person object and have a pointer point to that object. I can then try to make a Programmer pointer point to that Person object as well (by setting it equal to the Person pointer). If I used my Programmer pointer to try and make the Person object code (equivalent to calling a Programmer member function) or do something only a Programmer does, it wouldn't work because the Person hasn't been specialized.
I assume your question is why following should not be done:-
Derived *ptr = new Base; //assume for now public inheritance.
Derived is specialization of Base i.e Derived would inherit all features of base plus it could also add some of its own features. That means assigning Base to Derived ptr leads to loss of those features which could result into undefined behavior if call is made to that variable/method.
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.
I have a virtual class that has been derived from a non virtual class. But when I c-style cast the derived class to base class, the class is corrupted. I am looking at the member variables using the debugger and the member variables are all corrupted when I do that cast. I see there is a 4 byte discrepency when I do that cast(may be the virtual pointer) using debugger.
For Ex:
class A//non-virtual class
{
~A();
int fd;
};
class B:public A
{
virtual ~B();
};
Now say the address of obj of type B is: 0x9354ed0.
Now when I cast it (A*)(0x9354ed0) debugger moves the bytes by 4 bytes. So starting address of the casted obj is 0x935ed4
Is it wrong to cast a derived virtual class to base non-virtual class? What is the reason for 4 byte discrepancy?
And what is the right way to cast it? Thanks for any input or explanation.
Here is what you described.
class A
{
public:
~A();
// other stuff
};
class B: public A
{
public:
virtual ~B();
// other stuff
};
It is perfectly legal to derive a class from a non-virtual base class, and to make the derived class virtual. The 4 bytes offset (can be 8) corresponds to a hidden member variable of type pointer that points to the virtual functions table of the class.
When you cast pointers across the hierarchy, actual numerical pointer values might change. There's nothing wrong with the fact that it changes. There's noting wrong with such a cast. How the numerical pointer values change depend on the physical layout of the class. It is an implementation detail.
In your example, the 4 byte change in pointer value might easily be caused by the presence of virtual table pointer in the derived class.
The change in pointer value will not corrupt any member variables. The example in your original post does not show any "corrupted member variables" and in general your claim about some member variables getting "corrupted" doesn't make much sense. Please, when you make such claims, illustrate them with an example, so that people can understand what on Earth your are talking about.
Update:
The fact that base class subobjects might have non-zero offsets inside the derived classes immediately mean that in order to perform a proper cast from derived pointer type to base pointer type the compiler must know the source type and the destination type and the relationship between them. For example, if you do this
B* pb = /* whatever */;
A* pa = pb;
the compiler will know how to properly offset pointer pa from pointer pb. But of you do this
A* pa = (void *) pb;
the compiler will forget about the relationship between A and B, fail to perform the proper offset and produce the invalid value of pa. The effect would be the same as in
A* pa = reinterpret_cast<A*>(pb);
If you do it this way, the result will be meaningless. So, just don't do it.
Of course, if you manually inspect the numerical value of pb and find out that it is, say, 0x12345678, and then do
A* pa = (A*) 0x12345678;
you will also get completely meaningless results, because the computer has no way to know that it has to perform the proper offset of the pointer.
This will produce an illusion of members of A getting "corrupted", while in fact the only thing that is corrupted is your pointer. And you are the one who corrupted it.
If that is the shell of the code you are using then you aren't deriving the class B from class A. If you wanted to do that you would need to do this:
class A
{
public:
virtual ~A();
// other stuff
};
class B: public A
{
public:
virtual ~B();
// other stuff
};
I really don't think you can cast the way that you were hoping to in your question. If you are using virtual functions and derived classes then they need to be declared virtual upon first usage. Plus, I'm not 100% sure but if you have any virtual destructors you need to have all virtual destructors in your heirarchy.
Hope that helps,
nmr
The missing four bytes are, indeed, the vptr of the object; since class A has no vtable, a pointer to A has no vptr.
While it is actually legal deriving a class with virtual methods from another class with none, it is not a good idea. Inheriting from a class with no virtual methods is usually unsound, since that class is not intended to be used polymorphically, which is the main reason behind inheritance. All kinds of bad things can happen if you do it. If you try to use derived class objects through base class pointers, you may well run into the dreaded undefined behaviour (most likely a crash). For instance, trying to delete a base class pointer pointing to a derived class object.
Its legal to point derived class object using base class pointer
that's called run time polymorphism i.e. based on dynamic type of object functions are dispatched.
When you define a class with virtual function,a table comprising of virtual function address is formed called virtual function table.
When you declare an object of a class with virtual function , a virtual pointer pointing to corresponding virtual function table is insert into it.