downcast problem in c++ - c++

#include <iostream>
using std::cout;
using std::endl;
class Base
{
public :
void f();
void g();
int mBaseData1;
};
class Derived : public Base
{
public :
int mDerivedData1;
};
void main()
{
Base* base = new Base();
Derived* derived = (Derived*)(base); // DownCast
derived->mDerivedData1 = 6;
cout<< derived->mDerivedData1<<endl; // Result = 6;
}
in this code new base() allocate memory in heap
and Derived* derived = (Derived*)(base) cast base to derived
how we can use mDerivedData1? i cant find where we allocate memory for mDerivedData1 or when we call constructor of Derived for allocate mDerivedData1 ?

The reason you can't find where memory for mDerivedData1 was allocated is because no memory was allocated. You have performed an invalid type-cast. The thing stored in base is a pointer to a Base instance. Using a type-cast to tell the compiler that it's actually a pointer to a Derived instance doesn't make it so (but the compiler will believe you anyway because you're the one in charge). The object is still just a Base. If you want a Derived, then you'll need to instantiate a Derived. You can use dynamic_cast to convert the Base pointer into a Derived pointer.
Base* base = new Derived;
Derived* derived = dynamic_cast<Derived*>(base);
derived->mDerivedData1 = 6;

It will work correctly if you change:
Base* base = new Base();
to:
Base* base = new Derived();
but in general you should never downcast unless you are really sure you know what you are doing, and even then it's usually a sign of a very bad design.

You are really overwritting some part of the heap that is not part of the original base object. This could overwrite another object on the heap, or other unexplained happenings could occur.
C++ lets you do what you tell it to do for the most part. You are shooting yourself in the foot. :)

Your program exhibits undefined behavior. You cannot access mDerivedData1 because you don't actually have an instance of Derived.

You can cast an instance of a child class to a base class, but you cannot (well... should not) cast an instance of a base class into a child class.
Edit:
If you are confused about how casting works:
An object never actually changes during a cast -- in truth an object is really just a contiguous block of memory. When an object is cast, the only thing that changes is how the program sees and works with the object.
That's why casting an instance of a base object to a child object results in undefined behavior; the runtime interprets the base object as a child object and uses the pointer for the object as a starting point for referencing data of the object. If a field that is defined on the child class is used on a base object cast as the child object, the program will reference memory that is not part of the instance. If this referenced memory happens to be unused by the rest of the program, things might seem just fine (for a little while), but if the memory is used by another object, strange things could happen in your program -- the other object might have a value changed that it shouldn't have, or worse. And this is just when dealing with heap allocated objects; try this with a pointer to a stack allocated object and you could totally derail your entire program -- assuming you don't segfault.
So in general, if B derives from A:
You can cast an instance of B to A
You can cast an instance of B that is already cast as an A back to B, but this may indicate sloppy architecture of your program.
You cannot (should not) cast an instance of A to B, as this will result in undefined behavior.

Related

I thought pointers could only point to the same class/datatype?

I thought i knew pointers but then as i study run time polymorphism/dynamic binding, i've seen a very different use for pointers. Here are my 3 questions, they're all regarding the single line code below:
#include <iostream>
class Base {
public:
virtual void fun (int x) { std::cout << "base" << std::endl; }
};
class Derived : public Base {
public:
void fun (int x) { std::cout << "base" << std::endl; }
};
int main() {
//--------------------------------------
//1. Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
//2. What's the point of putting this into heap?
//3. I thought pointers could only hold memory address of the same datatype/class
Base* obj = new Derived();
//--------------------------------------
obj->fun(5);
return 0;
}
Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
The expression here is not Derived() (which would indeed construct a temporary object), but new Derived(), which is new's specific syntax to allocate and construct an object with dynamic lifetime and return a pointer to it. Note that the corresponding delete to end the object's lifetime is missing, but see the next point.
What's the point of putting this into heap?
None. In particular, the lifetime of an object does not affect the use of pointers with it, nor are pointers required for polymorphism (references work just as well). In any case, dynamic allocation should be done with smart pointers, not naked news.
I thought pointers could only hold memory address of the same datatype/class
That's still true: obj is pointing at the Base subobject of the Derived object. C++ provides an implicit pointer-adjusting conversion from Derived * to Base * (and Derived & to Base & as well) to facilitate the use of polymorphism.
Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
A new expression does multiple things. First, it allocates enough memory for the type of object. Then, it calls the constructor for that type at the allocated memory. Then, it returns a pointer to the newly created object. Pointers point to objects. new returns a pointer to an object. So there is no problem here, obj will now point to the newly created Derived object.
What's the point of putting this into heap?
It isn't strictly necessary to dynamically create an object here. You could just as easily have the following and illustrate polymorphism :
Derived foo;
Base* obj = &foo;
Maybe the author of this example didn't think of that, or maybe they wanted to illustrate the mechanics of new at the same time. You'd have to ask them.
I thought pointers could only hold memory address of the same datatype/class
It is true that obj is a Base* so it can only point to a Base type object. But a Derived object is also a Base object, so obj can easily point to a Derived object. That is what public inheritance achieves. The : public Base part of class Derived : public Base means Derived is also a Base.
Pointers can point to anything with a memory address.
A pointer to an instance of a derived class can be handled as if it were a pointer to the base class, even if the base class itself is abstract (unable to be instantiated itself). That's how polymorphism works in C++.
Why put a pointer to an object on the stack and the object itself into the heap? Many reasons, some of them good and others not so good.

C++ typechecks performed when assigning one pointer to another

I am wondering the extend of type checks the compiler does in the following
class Parent{
};
class Child : public Parent{
};
class Unrelated{
};
main(){
Parent* p = new Child() // OK. But type of p is still Parent* and not Child*
Unrelatead* u = new Child() // Not OK. Child* is not Unrelated*.
}
So, in the first assignment, the p now points to the 'Parent' object within Child, whereas the second assignment is not allowed at all, although ultimately both p and u will hold memory addresses.
What exactly checks does the compiler perform during these assignments and at what part of compilation does the compiler enforce these checks?
The first assignment is okay, because compilers will arrange all the memory of the base class in front of the memory of the derived class.
You can thus upcast pointers, since all the fields of the base class will still be pointed to.
The second assignment is not okay, because Child does not inherit from Unrelated and so their memory layout may be different.
The compiler keeps track of these class hierarchies.
These checks only happen at compile-time.
Note that upcasting pointers can be dangerous.
If your class is not virtual, delete p will not call the destructor of the derived class, leading to potential memory leaks.
If you decide to upcast and delete pointers, make sure you are doing it for virtual classes.
The compiler allows assigning data pointers:
When both are pointers to the same type, or the destination pointer is a pointer to a more restrictively const/volatile qualified type, e.g. T* to T const volatile*.
A pointer to a derived class can be assigned to a pointer to an accessible base class with a similar or more restrictive const/volatile qualification, e.g. Derived* to Base const*.
Any data pointer to void* with a similar or more restrictive const/volatile qualification, e.g. T const* to void const*.
Parent* p = new Child(); compiles because it is case 2.
Unrelatead* u = new Child(); doesn't compile because it is none of the above cases. To make the assignment between unrelated data pointers work a reinterpret_cast<> is required.

Assign a pointer with the address of different data type without casting

I've never seen this kind of code before:
(Class B is a subclass of ClassA)
ClassB objB;
ClassA *ptrA = &objB; // Question1
ClassA objA = *ptrA // Question2
Question1:
Why this assignment is valid?
What's the difference compared to
Class B objB;
Class A *ptrA;
ptrA = (ClassA*)&objB;
or
ClassB *ptrA;
ptrA = new classB;
Question2:
This line is valid too. Though the concept seems very similar to previous one but I don't know how it works.
Could anyone please tell me why these assignment are valid?
In C++ a base class pointer can point to a oblect of derived class. This language rule makes these statements valid in C++.
First, this is allowed because this will not create any problem since accessing the oblect using base class pointer will not access any memory or function not defined. since anything defined in base class is also defined in subclass/derived class too.
This feature allows dynamic polymarphism. In which the derived classes can implement diffrent functionalities and a single base class pointer will invoke the functions for derived class objects and the function will be called depending on the typee of the object pointed by base class pointer. This feature wouldn't possible without allowing a base pointer point to derivd class object and invoke functions.
ClassA *ptrA = &objB; // Question1
Why this assignment is valid?
Because that's how polymorphic inheritance works. A ClassB is a ClassA; so a reference/pointer to ClassB can convert to a reference/pointer to ClassA.
ptrA = (ClassA*)&objB;
That's doing the same thing, but making the cast explicit. This is much more dangerous though - the evil C-style cast will allow any pointer conversion, whether or not it's valid, while the original implicit conversion will only allow safe conversions (as the derived-to-base pointer conversion is).
ptrA = new classB;
That creates a dynamic object, giving you a pointer to that; the original sets the pointer to point to an existing object. Don't use new unless you really need it.
ClassA objA = *ptrA // Question2
This is sometimes known as slicing. If the base class is copyable (as it presumably is here), then the base sub-object can be copied to make a new object of that type. Technically, *ptrA is converted to a reference to ClassA (since such a conversion is allowed, just as the previous pointer conversion is); then that reference is used to copy-initialise objA.
Slicing can cause confusion; but it's not an issue if you only use abstract base classes, since they can't be instantiated directly.
This is called polymorphism. It is one of the most important key features of all object oriented programming languages.
Polymorphism means that instances of type B can be treated as instances of type A if B is derived from A.
Regarding Question2, there are two possible outcomes here:
ClassA *ptrA = &objB;
ClassA objA = *ptrA; // Question2
If no copy operator exists, only data fields from ClassA a scope are copied over and rest of the data is lost. This can be potentially dangerous, since the wrong vtable for virtual classes might be copied over. This is known as Object Slicing.
If ClassA::operator=(const ClassA& rhs) exists, then the problem solves itself. Just make sure to implement correct logic in the copy operator.
If you don't take extra care with writing proper copy logic for your classes, your code will definitely break during runtime. I really recommend 'Effective C++' if you haven't picked it up yet - it gives a very good shortcut into the world of C++.

C++, what does pointer really mean? when virtual involved

For the following code
class A
{
public:
~A()
{
std::cout << "a" << std::endl;
}
};
class B : public A {
public:
virtual ~B()
{
std::cout << "b" << std::endl;
}
};
int main()
{
B* b = new B();
A* a = b;
if (a == b)
{
}
delete a;
}
Question is , will “a” equals to “b” ? Why and How this happened?
And what a pointer really means? Not just an address and the length of the memory block?
will “a” equals to “b” ?
Yes
Why and How this happened?
To perform the comparison of the two pointers the compiler will perform a conversion to a common type. In this case, as A is a base of B, the conversion is to A*, yielding code equivalent to:
A* __tmp = b;
if ( a == __tmp ) ...
And what a pointer really means? Not just an address and the length of the memory block?
A pointer is a variable the holds the address of an object (no size information stored in the pointer). But the pointer has a type, and the compiler will interpret the memory location that the pointer refers to be an object of that type. That extra information that is stored outside of the pointer is what allows the compiler to perform the conversion.
The a variable will point at the A class portion of the allocated b object. A pointer is just a memory address, nothing more. What is important is what kind of data the pointer is pointing at in memory.
Let's split the answer in three parts
Pointers
A pointer is a variable which holds the memory address of another variable. The type of the pointed variable is important and will be checked by the compiler. One can force the pointer mechanic by using pointers to void (should be avoided in C++, unless you really know what you are doing).
Accessing derived class objects using base class pointers
An object, i.e. a variable, of a derived class (b in your code) can be referred to using a pointer to its parent type (A in your code). This will allow you to access the members of A that are present in B. As already stated by Richard J. Ross, using a pointer to the base class will yield the same address as using the derived class pointer (unless multiple inheritance is involved).
Virtual functions
Virtual methods allow you to call an overloaded method of the derived object using a base class pointer. This is especially useful for destructors because one can rest assured that objects will be properly destroyed even when using a base class pointer (assuming the destructor is well written).
Still, your code is conceptually wrong. Because the destructor of A is not virtual, the destructor of the B part of b will not be called, hence there might be memory leaks and similar problems.
As David already mentioned, simple comparison of two pointers a == b will give you True because the compiler will cast both of them to the common type.
But, if you were to modify this to (void*)a == (void*)b, result may be false.
This is because classes A and B have different memory layouts due to B having a virtual function table and A - not.
MSVC compiler puts virtual function pointer on the "top" of the class, before the first data member, but nothing stops other compilers from placing it on the "bottom".
You may also try making class A destructor virtual.
I found some explain on inside c++ object model, this is just like multiple inheritance, the vptr locates at the beginning of the object.
when the base class having no virtual and child class having a virtual, the assign of pointer will be adjusted by the compiler by step over the vptr,
The example is a comparison between two pointers. As they are pointing to the same location, a will be equal to b.

boost::shared_ptr and assigning derived classes

Assume DerivedClass is derived from BaseClass
Would the following work?
boost::shared_ptr<BaseClass> a(new BaseClass());
boost::shared_ptr<DerivedClass> b(new DerivedClass());
a=b;
Following this question, I understand that now a points to the derived and b points to the base (right?)
Also, now if I call a function via a would it call the derived implementation?
...
a=b;
You are reassigning to a and therefore a and b would now both point to the DerivedClass object. The BaseClass object would be destroyed, since its reference count would be zero at this point (by virtue of a being reasigned to point to a different object).
Since a now points to a DerivedClass object, virtual function calls (defined in BaseClass and overriden in DerivedClass) via a would call the corresponding member functions in DerivedClass.
When both a and b go out of scope, the DerivedClass object would be destroyed.
If you need to access functions specific to the derived class via a (e.g., non-virtual functions in DerivedClass), you can use:
boost::dynamic_pointer_cast<DerivedClass>(a)->SomeFunctionOnlyInDerivedClass();
Of course this is just a terse example that shows usage. In production code, you would almost certainly test for a successful cast to the DerivedClass, before dereferencing the pointer.
Assume DerivedClass is derived from BaseClass. Would the following work?
Yes. Just as there's nothing wrong with
boost::shared_ptr<BaseClass> pbase(new DerivedClass());
(Assuming in both cases that BaseClass has a virtual destructor.) The smart pointer is designed to behave like a plain pointer as much as possible, and provide the same behaviour as BaseClass* pbase = new DerivedClass();, plus all that lifetime-management goodness.
Following this question, I understand that now a points to the derived and b points to the base (right?)
No, a and b would both point to the DerivedClass instance. The swap that the linked article refers to happens on a temporary object inside operator=. When that temporary object goes out of scope, the BaseClass instance would be deleted.
Also, now if I call a function via a would it call the derived implementation?
Yes. If you look at the implementation of operator->, all it does is return the pointer which the fundamental operator-> is to be called on:
T * operator-> () const // never throws
{
BOOST_ASSERT(px != 0);
return px;
}
so that the behaviour is the same as a plain pointer.
When doing a=b you tell a to point to the object b also points to. So all methods you call, you call on the BaseClass part of the object b points to.
So if it contains a virtual method that is overwritten in DerviedClass, the the overwritten version is called.