In what situations / circumstances a dynamic_cast<> can fail? - c++

While fixing a bug in a huge code base, I am observing a strange situation, where the dynamic type of a reference changes from Original Derived type to Base type! I am providing the minimal code to explain the problem:
struct Base {
// some 'virtual' function
protected: // copy constructor
private: // assignment operator
};
struct Derived : Base {
... // There are few more classes between `Base` and `Derived`
... // but for simplicity, I have put direct relation
};
void foo (Base &ref)
{
SomeClass obj;
obj.pVoid = &ref; // pVoid is of void*
// ----> typeid(ref) = Derived
(*funcptr)(obj);
// ----> typeid(ref) = Base !!!
Derived *p = dynamic_cast<Derived*>(&ref); // this fails ... i.e. "p = 0"
}
funcptr is a function pointer (void (*)(SomeClass&)). funcptr can point to so many functions and they have their own call flows, so it would be difficult to debug.
It's very strange that after the call to function pointer, the derived type of ref changes from Derived to Base. To ease my work, I suspected object slicing from Derived to Base, so I made ~Base() as pure virtual and re-compiled the whole source code. But there was no compiler error, which means that there is no object of Base being declared.
What are the potential reasons, that the dynamic type of ref Derived is changed to Base and the dynamic_cast fails later on ?

I don't believe that the above code is like it actually is because the code example doesn't compile! You cannot implicitly convert a Base* resulting from the dynamic_cast<Base*>(&ref) to Derived*.
That said and assuming that the outputs of the typeid() are actually correct there are a few viable explanations of the type ID of the reference changing. All of these indicate an error in the program in some form or the other:
The called function destroys the object e.g. by calling the moral equivalent of dynamics_cast<Base*>(obj.pVoid)->~Base().
The called function constructs a new object at the address pointed to by obj.pVoid using placement new, i.e. something like this: new(obj.pVoid) Base().
Something is overwriting memory, resulting in leaving a Base object in the referenced location.
There are probably more reasons...
Personally, I would gamble on the second case being case, i.e. an object is constructed into the location. Obviously, without seeing the function being called it is impossible to tell.

dynamic_cast (to a pointer) can return 0 if the conversion is ambiguous. To illustrate:
class O {…};
class A : public virtual O {…};
class B : public A {…};
class C : public A {…};
class D : public B, public C {…};
void f(O& p) {
A* const a(dynamic_cast<A*>(&p));
}
void g() {
D d;
f(d);
}

The reason for which the dynamic_cast<> was failing in my specific case is due to deleteing the reference prematurely!
Once a pointer or reference is delete + destructed, then any attempt to downcast it to the original type would result in entering the "undefined behavior" region. In my case the dynamic_cast<> is failing.
void foo (Base &ref)
{
SomeClass obj;
obj.pVoid = &ref;
(*funcptr)(obj); // ----> delete (Base*)(obj.pVoid); in one of the callbacks
Derived *p = dynamic_cast<Derived*>(&ref); // fails => "p = 0"
}

Related

How to pass pointer of derived class to reference to pointer of base class?

Here is the sample code.
class BaseClass {
};
class DerivedClass : public BaseClass {
};
int Foo(BaseClass*& ptr) {
}
DerivedClass* ptr_to_derived;
//following will not work
Foo(ptr_to_derived);
I fail to compile code above, and the error message is "can't convert DerivedClass* to BaseClass*&". So How can I pass ptr_to_derived to Foo?
The error message is quite clear:
error: invalid initialization of non-const reference of type
‘BaseClass*&’ from an rvalue of type ‘BaseClass*’
Because Foo takes a pointer by non-const reference you can't pass it an rvalue. The implicit conversion from DerivedClass to BaseClass that happens when you pass it to Foo gets you the rvalue that the error is complaining about.
You can create a base pointer from the derived one and pass that:
DerivedClass* ptr_to_derived;
BaseClass* ptr_derived_base = ptr_to_derived;
Foo(ptr_derived_base);
The problem is that Foo might modify the passed pointer-to-base. For example:
class OtherDerivedClass : public BaseClass {
};
OtherDerivedClass* ptr_to_other_derived = ...;
void Foo(BaseClass*& ptr)
{
ptr = ptr_to_other_derived;
}
What do you think should happen if you could call this Foo with ptr_to_derived? Should ptr_to_derived now point not to a DerivedClass but to an OtherDerivedClass object? That's wrong on every level.
Solution 1: Don't allow Foo to modify the pointer. Either pass by value:
void Foo(BaseClass* ptr)
or by const-ref:
void Foo(const BaseClass*& ptr)
Solution 2: Create a pointer-to-base variable that Foo can modify.
BaseClass* ptr_to_base = ptr_to_derived;
foo(ptr_to_base);
This will of course leave ptr_to_derived unmodified. C++ does not let you pass a temporary expression (which is what the conversion from DerivedClass* to BaseClass* would return) because, again, Foo says it will modify that pointer and the changed temporary would just be discarded. That's usually a mistake. You could of course still decide to not care about the change to ptr_to_base that Foo might make.
You cannot do that.
What you can do is convert to a pointer to a base, store that converted pointer somewhere (such as variable), and pass that by lvalue reference. The reference cannot refer to the derived pointer. Like so:
BaseClass* ptr_to_base = ptr_to_derived;
Foo(ptr_to_base);
However, it would be better to pass the pointer by value in order to avoid this hassle. Or preferably even pass a reference instead of a pointer to the base in case that is sufficient. Like so:
int Foo(BaseClass& ref)
With this you can call:
DerivedClass1 d1;
DerivedClass2 d2;
Foo(d1);
Foo(d2);
// or with pointers
DerivedClass1* d1_ptr = &d1;
DerivedClass2* d2_ptr = &d2;
Foo(*d1_ptr);
Foo(*d2_ptr);
This is illegal for good reasons, look at following code:
class BaseClass {};
class DerivedClass :public BaseClass {};
class DerivedClass2 :public BaseClass {};
DerivedClass2 derived2;
void Foo(BaseClass*& ptr) {
ptr = &derived2; // Legal.
}
DerivedClass* ptr_to_derived = nullptr;
then if legal, Foo(ptr_to_derived) would make ptr_to_derived to unrelated DerivedClass2 which is wrong.

Why does a base pointer can access derived member variable in virtual funtion

class Base {
public:
virtual void test() {};
virtual int get() {return 123;}
private:
int bob = 0;
};
class Derived: public Base{
public:
virtual void test() { alex++; }
virtual int get() { return alex;}
private:
int alex = 0;
};
Base* b = new Derived();
b->test();
When test and get are called, the implicit this pointer is passed in. Is it because Derived classes having a sub memory layout that is identical to what a pure base object would be, then this pointer works for both as a base pointer and derived pointer?
Another way to put it is, the memory layout for Derived is like
vptr <-- this
bob
alex
That is why it can use alex in b->test(), right?
Inside of Derived's methods, the implicit this pointer is always a Derived* pointer (more generically, the this pointer always matches the class type being called). That is why Derived::test() and Derived::get() can access the Derived::alex member. That has nothing to do with Base.
The memory layout of a Derived object begins with the data members of Base, followed by optional padding, followed by the data members of Derived. That allows you to use a Derived object wherever a Base object is expected. When you pass a Derived* pointer to a Base* pointer, or a Derived& reference to a Base& reference, the compiler will adjust the pointer/reference accordingly at compile-time to point at the Base portion of the Derived object.
When you call b->test() at runtime, where b is a Base* pointer, the compiler knows test() is virtual and will generate code that accesses the appropriate slot in b's vtable and call the method being pointed at. But, the compiler doesn't know what derived object type b is actually pointing at in runtime (that is the whole magic of polymorphism), so it can't automatically adjust the implicit this pointer to the correct derived pointer type at compile-time.
In the case where b is pointing at a Derived object, b's vtable is pointing at Derived's vtable. The compiler knows the exact offset of the start of Derived from the start of Base. So, the slot for test() in Derived's vtable will point to a private stub generated by the compiler to adjust the implicit Base *this pointer into a Derived *this pointer before then jumping into the actual implementation code for Derived::test().
Behind the scenes, it is roughly (not exactly) implemented like the following pseudo-code:
void Derived_test_stub(Base *this)
{
Derived *adjusted_this = reinterpret_cast<Derived*>(reinterpret_cast<uintptr_t>(this) + offset_from_Base_to_Derived);
Derived::test(adjusted_this);
}
int Derived_get_stub(Base *this)
{
Derived *adjusted_this = reinterpret_cast<Derived*>(reinterpret_cast<uintptr_t>(this) + offset_from_Base_to_Derived);
return Derived::get(adjusted_this);
}
struct vtable_Base
{
void* funcs[2] = {&Base::test, &Base::get};
};
struct vtable_Derived
{
void* funcs[2] = {&Derived_test_stub, &Derived_get_stub};
};
Base::Base()
{
this->vtable = &vtable_Base;
bob = 0;
}
Derived::Derived() : Base()
{
Base::vtable = &vtable_Derived;
this->vtable = &vtable_Derived;
alex = 0;
}
...
Base *b = new Derived;
//b->test(); // calls Derived::test()...
typedef void (*test_type)(Base*);
static_cast<test_type>(b->vtable[0])(b); // calls Derived_test_stub()...
//int i = b->get(); // calls Derived::get()...
typedef int (*get_type)(Base*);
int i = static_cast<get_type>(b->vtable[1])(b); // calls Derived_get_stub()...
The actual details are a bit more involved, but that should give you a basic idea of how polymorphism is able to dispatch virtual methods at runtime.
What you've shown is reasonably accurate, at least for a typical implementation. It's not guaranteed to be precisely as you've shown it (e.g., the compiler might easily insert some padding between bob and alex, but either way it "knows" that alex is at some predefined offset from this, so it can take a pointer to Base, calculate the correct offset from it, and use what's there.
Not what you asked about, so I won't try to get into detail, but just a fair warning: computing such offsets can/does get a bit more complex when/if multiple inheritance gets involved. Not so much for accessing a member of the most derived class, but if you access a member of a base class, it has to basically compute an offset to the beginning of that base class, then add an offset to get to the correct offset within that base class.
A derived class is not a seperate class but an extension. If something is allocated as derived then a pointer (which is just an address in memory) will be able to find everything from the derived class. Classes don't exist in assembly, the compiler keeps track of everything according to how it is allocated in memory and provides appropriate checking accordingly.

What is the underlying mechanism of a base class pointer assigned to derived class

Similar questions I found were more based on what this does; I understand the assignment of a base class pointer to a derived class, e.g Base* obj = new Derived() to be that the right side gets upcasted to a Base* type, but I would like to understand the mechanism for how this happens and how it allows for virtual to access derived class methods. From searching online, someone equated the above code to Base* obj = new (Base*)Derived, which is what led to this confusion. If this type-casting is going on at compile-time, why and how can virtual functions access the correct functions (the functions of the Derived class)? Further, if this casting happens in the way I read it, why do we get errors when we assign a non-inheriting class to Base* obj? Thanks, and apologies for the simplicity of the question. I'd like to understand what causes this behavior.
Note: for clarity, in my example, Derived publicly inherits from Base.
In a strict sense, the answer to "how does inheritance work at runtime?" is "however the compiler-writer designed it". I.e., the language specification only describes the behavior to be achieved, not the mechanism to achieve it.
In that light, the following should be seen as analogy. Compilers will do something analogous to the following:
Given a class Base:
class Base
{
int a;
int b;
public:
Base()
: a(5),
b(3)
{ }
virtual void foo() {}
virtual void bar() {}
};
The compiler will define two structures: one we'll call the "storage layout" -- this defines the relative locations of member variables and other book-keeping info for an object of the class; the second structure is the "virtual dispatch table" (or vtable). This is a structure of pointers to the implementations of the virtual methods for the class.
This figure gives an object of type Base
Now lets look as the equivalent structure for a derived class, Derived:
class Derived : public Base
{
int c;
public:
Derived()
: Base(),
c(4)
{ }
virtual void bar() //Override
{
c = a*5 + b*3;
}
};
For an object of type Derived, we have a similar structure:
The important observation is that the in-memory representation of both the member-variable storage and the vtable entries, for members a and b, and methods foo and bar, are identical between the base class and subclass. So a pointer of type Base * that happens to point to an object of type Derived will still implement an access to the variable a as a reference to the first storage offset after the vtable pointer. Likewise, calling ptr->bar() passes control to the method in the second slot of the vtable. If the object is of type Base, this is Base::bar(); if the object is of type Derived, this is Derived::bar().
In this analogy, the this pointer points to the member storage block. Hence, the implementation of Derived::bar() can access the member variable c by fetching the 3rd storage slot after the vtable pointer, relative to this. Note that this storage slot exists whenever Derived::bar() sits in the second vtable slot...i.e., when the object really is of type Derived.
A brief aside on the debugging insanity that can arise from corrupting the vtable pointer for compilers that use a literal vtable pointer at offset 0 from this:
#include <iostream>
class A
{
public:
virtual void foo()
{
std::cout << "A::foo()" << std::endl;
}
};
class B
{
public:
virtual void bar()
{
std::cout << "B::bar()" << std::endl;
}
};
int main(int argc, char *argv[])
{
A *a = new A();
B *b = new B();
std::cout << "A: ";
a->foo();
std::cout << "B: ";
b->bar();
//Frankenobject
*((void **)a) = *((void **)b); //Overwrite a's vtable ptr with b's.
std::cout << "Franken-AB: ";
a->foo();
}
Yields:
$ ./a.out
A: A::foo()
B: B::bar()
Franken-AB: B::bar()
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
...note the lack of an inheritance relationship between A and B... :scream:
Whoever says
Base* obj = new Derived();
is equivalent to
Base* obj = new (Base*)Derived;
is ignorant of the subject matter.
It's more like:
Derived* temp = new Derived;
Base* obj = temp;
The explicit cast is not necessary. The language permits a derived class pointer to be assigned to a base class pointer.
Most of the time the numerical value of the two pointers are same but they are not same when multiple inheritance or virtual inheritance is involved.
It's the compiler's responsibility to make sure that numerical value of the pointer is offset properly when converting a derived class pointer to a base class pointer. The compiler is able to do that since it makes the decision about the layout of the derived class and the base class sub-objects in the derived class object.
If this type-casting is going on at compile-time, why and how can virtual functions access the correct functions
There is no type casting. There is a type conversion. Regarding the virtual functions, please see How are virtual functions and vtable implemented?.
Further, if this casting happens in the way I read it, why do we get errors when we assign a non-inheriting class to Base* obj?
This is moot since it does not happen the way you thought they did.

What happens when an upcast pointer is passed by reference to a function expecting derived?

I've inherited something similar to this code:
class Base
{
public:
virtual double getElement(int i) {return NULL;}
virtual Derived* GetAsDerived() {return this;}
};
class Derived : public Base
{
public:
virtual double getElement(int i) {return vec[i];}
private:
std::vector<double>;
};
And a function as follows:
void f(Base& b)
{
Derived* d = b.GetAsDerived();
}
The program flow is something similar to this
Derived A;
/* get data into vector in A */
f(A);
After the call to GetAsDerived() in f .The vector in the object pointed by d contains junk.Inside the debugger I can go back in the call stack and see that the vector inside A still has valid data.
I am sure that that all this weird upcasting - downcasting is the cause but I was not able to find a formal explanation in the specs or online.
So why does it fail in such a manner?
Upcasting is formally defined in 4.10/3 of the standard. Downcasting is in 5.2.9/5, although that's not specifically what you're doing.
Addressing the title of your question, it's not possible to pass (or return) a base class pointer to (from) a function whose parameters (return type) indicate a derived class pointer. If the parameters indicate a reference to base class pointer, then it's not possible to pass a derived class pointer by reference. If a base class pointer value, it is possible to pass a derived pointer because of the implicit conversion.
I can't say why your code fails: as commented above, your real code must fail for different reasons than your example code does, since your example code doesn't work at all.
In function f,Derived* d = b.GetAsDerived();does not change anything about b,so it can't change the object b points to,in this case A.In f,If there is b = d or something alike,then A will be changed.

How do I know which function will be called?

Today I found the following disturbingly ambiguous situation in our code base:
class Base {
public:
virtual void Irrelevant_Function(void) = 0;
protected:
C_Container * Get_Container(void);
};
class A : public Base, public Not_Important {
public:
inline C_Container * Get_Container(void);
};
class B : public Base, protected SomethingElse {
public:
C_Container * Get_Container(void);
};
Many things were calling the Get_Container method, but not always calling the correct one - note that none of these functions were virtual.
I need to rename the methods Get_Base_Container, Get_A_Container, etc to remove the ambiguity. What rules does C++ use to determine which version of a function it should call? I'd like to start from the "known state" of what should have been getting called, and then figure out the bugs from there.
For example, if I have a pointer to a Base and call Get_Container, I assume it would just call the Base version of the function. What if I have a pointer to an A? What about a pointer to a B? What about an A or B on the heap?
Thanks.
It depends how you're calling the function. If you're calling through an A *, an A & or an A, then you'll be calling A::Get_Container(). If you're calling through a Base *, a Base & (even if they point to/reference an A), then you'll be calling Base::Get_Container().
As long as there's no virtual inheritance going on, it's quite easy. If you're working directly with an object, it's the object's method that gets called; if you're working with a pointer or reference, it's the type of the pointer or reference that determines the method, and the type of the object pointed to doesn't matter.
A method is first looked up according to the object's static type. If it is non-virtual there, you're done: that's the method that's called. The dynamic type is what virtual methods, dynamic_cast, and typeid use, and is the "actual" type of the object. The static type is what the static type system works with.
A a; // Static type and dynamic type are identical.
Base &a_base = a; // Static type is Base; dynamic type is A.
a.Get_Contaienr(); // Calls A::Get_Container.
a_base.Get_Container(); // Calls Base::Get_Container.
B *pb = new B(); // Static type and dynamic type of *pb (the pointed-to
// object) are identical.
Base *pb_base = pb; // Static type is Base; dynamic type is B.
pb->Get_Container(); // Calls B::Get_Container.
pb_base->Get_Container(); // Calls Base::Get_Container.
I've assumed above that the protected Base::Get_Container method is accessible, otherwise those will be compile errors.
A couple of additional points to note here:
Name lookup occurs in a single scope; E.g. When calling the method on an object with static type 'B', the compiler considers the interface of 'B' to determine whether or not there is a valid match. If there is not, it only then looks at the interface of Base to find a match. This is why that from the compiler's view, there is no ambiguity and it can resolve the call. If your real code has overloading etc. this may be an issue.
Secondly, it is often forgotten that the 'protected' keyword applies at class and not object level. So for example:
class Base {
protected:
C_Container * Get_Container(void);
};
class B : public Base{
public:
C_Container * Get_Container(void)
{
B b;
// Call the 'protected' base class method on another object.
return b.Base::Get_Container();
}
};