Multiple inheritance pointer comparison - c++

I have a class Derived that inherits directly from two base classes, Base1 and Base2. I'd like to know if it's safe, in general, to compare pointers to the base classes to determine if they are the same Derived object:
Base1* p1;
Base2* p2;
/*
* Stuff happens here. p1 and p2 now point to valid objects of either their
* base type or Derived
*/
//assert(p1 == p2); //This is illegal
assert(p1 == static_cast<Base1*>(p2)); //Is this ok?
assert(static_cast<Derived*>(p1) == static_cast<Derived*>(p2)); //How about this?
The pointers are guaranteed to be valid, but not necessarily to point to a Derived object. My guess is that this is probably fine, but I wanted to know if it was ok from a technical C++ perspective. I actually never do any operations on the pointers, I just want to know if they point to the same object.
EDIT: It seems to be safe if I can guarantee that p1 and p2 point to Derrived objects. I basically want to know if it is safe if they don't- if one or both point to a base object, will the comparison necessarily fail? Again, I can guarantee the pointers are valid (i.e., p1 would never point at a Base2 object or vice versa)

Well, no, it won't work.
I'm personally a big fan of learning-by-example, so here's one:
#include <iostream>
class Base1
{
public:
Base1()
{
numberBase1 = 1;
}
int numberBase1;
};
class Base2
{
public:
Base2()
{
numberBase2 = 2;
}
int numberBase2;
};
class Derived : public Base1, public Base2
{
public:
Derived()
{
numberDerived = 3;
}
int numberDerived;
};
int main()
{
Derived d;
Base1 *b1 = &d;
Base2 *b2 = &d;
std::cout << "d: " << &d << ", b1: " << b1 << ", b2: " << b2 << ", d.numberDerived: " << &(d.numberDerived) << std::endl;
return 0;
}
One run-through on my computer outputted this:
d: 0035F9FC, b1: 0035F9FC, b2: 0035FA00, d.numberDerived: 0035FA04
Soo.. If we define the address of d as 0, then b1 is 0, b2 is +4 and the number of d is +8. This is because an int on my machine is 4 byte long.
Basically, you have to look at the layout of how C++ internally represents a class:
Address: Class:
0 Base1
4 Base2
8 Derived
.. So in total, instantiating a Derived class will allocate space for the base classes of the derived class, and finally make room for the derived object itself. Since we have 3 integers here, that'll be 12 bytes.
Now, what you're asking (unless I misunderstood something) is if you can compare the address of the different base class pointers to each other to see if they point to the same object, and the answer is no - Not directly at least, as in my example, b1 would point to 0035F9FC, while b2 would point to 0035FA00. In C++, this offsetting is all done at compile time.
You could probably do some magic with RIIA and sizeof() and determine how much of an offset b2 should have to be comparable to b1, but then you run into all kinds of other trouble like virtuals. In short, I would not recommend this approach.
A much better way would be to cast to Derived* like ialiashkevich said, however, that would impose a problem if your object was not an instance of Derived*.
(Disclaimer; I haven't used C++ in 3-4 years, so I might be a bit off my game. Be gentle :) )

Casting to Derived* before comparison is the right way to go.
There is a similar topic: C++ pointer multi-inheritance fun

Well, turns out the shortest way to achieve what you're looking for is:
assert(dynamic_cast<void*>(p1) == dynamic_cast<void*>(p2));
Dynamically casting to void* effectively down-casts the given pointer to its most derived class, so you're guaranteed if both point on the same object, the assert won't fail.
Indeed, there are practical uses for dynamic-casting to void pointer...
Edit: to answer the question's edit, the comparison is not safe. Consider the following code:
Base2 b2;
Base1 b1;
assert(static_cast<Derived*>(&b1) == static_cast<Derived*>(&b2)); // succeeds!
The memory layout of the two different bases is similar to that of a Derived (on a common implementation - the stack grows opposite of the heap). The first static_cast leaves the pointer as is, but the second one moves the pointer sizeof(Base1) back, so now they both point on &b1, and the assert succeeds - even though the objects are different.
You should use static_cast only if you know for sure the cast is correct. This is not your case, so you must use dynamic_cast, possibly as suggested above.

The short answer is no, this is generally not a good idea.
NOTE: This is assuming you want custom equivalence for all of your classes, if you want to check if they are the same object, it is better to do (Derived *).
A much better solution would be to overload the == operator for Base1, Base2, and Derived.
Assuming Base1 has 1 parameter param1 for equality and Base2 has another parameter param2 for equality:
virtual bool Base1::operator==(object& other){
return false;
}
virtual bool Base1::operator==(Base1& other)
{
return this.param1 == other.param1;
}
virtual bool Base2::operator==(object& other){
return false;
}
virtual bool Base2::operator==(Base2& other)
{
return this.param2 == other.param2;
}
virtual bool Derived::operator==(object& other){
return false;
}
virtual bool Derived::operator==(Derived& other){
return this.param1 == other.param1 && this.param2 == other.param2;
}
virtual bool Derived::operator==(Base1& other){
return this.param1 == other.param1;
}
virtual bool Derived::operator==(Base2& other){
return this.param2 == other.param2;
}

It appears to be invalid, based on this SO question:
How is C++'s multiple inheritance implemented?
Basically, because of the way the objects are laid out in memory, a cast to either Base1* or Base2* results in a mutation of the pointer that I can't arbitrarily reverse at runtime without a dynamic_cast, which I'd like to avoid. Thanks everyone!

Use dynamic_cast, and watch out for NULL.
#include <cassert>
struct Base1 { virtual ~Base1() {} };
struct Base2 { virtual ~Base2() {} };
struct Derived : Base1, Base2 {};
bool IsEqual(Base1 *p1, Base2 *p2) {
Derived *d1 = dynamic_cast<Derived*>(p1);
Derived *d2 = dynamic_cast<Derived*>(p2);
if( !d1 || !d2 ) return false;
return d1 == d2;
}
int main () {
Derived d;
Base1 *p1 = &d;
Base2 *p2 = &d;
Base1 b1;
Base2 b2;
assert(IsEqual(p1, p2));
assert(!IsEqual(p1, &b2));
assert(!IsEqual(&b1, p2));
assert(!IsEqual(&b1, &b2));
}

assert(p1 == p2); //This is illegal
assert(p1 == static_cast<Base1*>(p2)); //Is this ok?
assert(static_cast<Derived*>(p1)
== static_cast<Derived*>(p2)); //How about this?
None of them is a good solution. The first one will not compile, as you cannot compare pointers of unrelated types. The second one will not compile either (unless Base1 and Base2 are related through inheritance) for the same reason: you cannot static_cast to a pointer of an unrelated type.
The third option is borderline. That is, it is not correct, but it will work in many cases (as long as inheritance is not virtual).
The proper way of comparing for identity would be using dynamic_cast to the derived type and checking for null:
{
Derived *tmp = dynamic_cast<Derived*>(p1);
assert( tmp && tmp == dynamic_cast<Derived*>(p2) );
{

Related

In a diamond inheritance structure, is there a way to cast between the branches?

I have a diamond inheritance structure in my code in which I have a pointer to the
bottom object. I tried to case this to a pointer to the left of the two diamond sides, cast it again to the top of the diamond, and again to the right side. But apparently, C++ kind of remembers the order of casting and things don't work as expected. Example code:
#include <iostream>
class A
{
};
class B1 : public A
{
public:
virtual int Return1() = 0;
};
class B2 : public A
{
public:
virtual int Return2() = 0;
};
class C : public B1, public B2
{
public:
virtual int Return1() { return 1; }
virtual int Return2() { return 2; }
};
int main()
{
C c;
B1* b1 = &c;
A* a = b1;
B2* b2 = (B2*)a;
std::cout << "Return2() = " << b2->Return2();
}
This results in Return2() = 1, so apparently this approach is wrong. I know that something like this works in C#, so my question would be: Is there a way in C++ to do what I'm attempting here or - if not - why is this not an option?
As inheritance is not virtual (for A), you have "Y" inheritance (2 A),
A A
| |
B1 B2
\ /
C
not a diamond (1 A).
Avoid C-cast which might result in reinterpret_cast, and most reinterpret_cast usage leads to Undefined Behavior (UB).
You might use dynamic_cast in your case to have expected behavior (A need to be polymorphic for that, default virtual destructor does the job):
class A
{
public:
virtual ~A() = default; // Added to allow dynamic_cast
};
class B1 : public A
{
public:
virtual int Return1() = 0;
};
class B2 : public A
{
public:
virtual int Return2() = 0;
};
class C : public B1, public B2
{
public:
// override used for extra check from compiler.
int Return1() override { return 1; }
int Return2() override { return 2; }
};
int main()
{
C c;
B1* b1 = &c;
A* a = b1;
B2* b2 = dynamic_cast<B2*>(a); // C-cast replaced by dynamic_cast
assert(b2 != nullptr);
std::cout << "Return2() = " << b2->Return2();
}
Demo
You can see the desired result by changing the last casting to:
B2* b2 = (B2*)&c;
This is an issue related to upcasting and downcasting.
The issue here is that you are using a C cast (T) expr, which is 99% of the time a bad idea in C++.
C casts only exist in C++ due to the need of being retrocompatible with C, and can behave in unexpected ways.
From here:
When the C-style cast expression is encountered, the compiler attempts to interpret it as the following cast expressions, in this order:
a) const_cast<new_type>(expression);
b) static_cast<new_type>(expression), with extensions: pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier). Same applies to casting pointer to member to pointer to member of unambiguous non-virtual base;
c) static_cast (with extensions) followed by const_cast;
d) reinterpret_cast<new_type>(expression);
e) reinterpret_cast followed by const_cast.
The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled (see example)
The correct type of cast when downcasting in C++ is dynamic_cast<T>(expr), which checks if the object of the expression can be cast to the derived type T before performing it. If you did that, you would have got a compile time or runtime error, instead of getting a wrong behaviour.
C-style casts never perform dynamic casts, so (B2*) in B2* b2 = (B2*)a becomes equivalent to reinterpret_cast<B2*> which is a type of cast that blindly coerces any pointer type to any other. In this way C++ can't do any of the required pointer "magic" it's usually needed to convert a C* into a valid B2*.
Given that polymorphism in C++ is implemented through virtual dispatching using method tables, and that the pointer in b2 doesn't point to the correct base class (given that it was actually a pointer to B1), you are accessing the vtable for B1 instead of B2 through b2.
Both Return1 and Return2 are the first functions in the vtables of their respective abstract classes, so in your case Return1 is mistakenly called - you could largely approximate virtual invocations with something like b2->vtable[0]() in most implementations. Given that neither of the two methods touch this, nothing breaks and the function returns without crashing the program (which is not guaranteed, given this whole thing is undefined behaviour).

Checking the original type of a converted object

I wanted to know if it's possible to get the original type of an object when held through a pointer to base class.
For example:
class Base {
virtual void f() = 0
};
class Derived: public Base {};
Base * ptr=new Derived;
//if I use
cout << typeid(ptr).name(); //prints Base*
I want it to print the original type "Derived". Is there a way to do it?
Yes, the static and dynamic type of ptr are both Base *. However, for *ptr, the situation is different. The static type is Base &, but the dynamic type is Derived &. So that's what you want to test:
cout << typeid(*ptr).name();
You can try with dynamic_cast
if(Derived* d = dynamic_cast<Derived*>(b1))
{
std::cout << "downcast from b1 to d successful\n";
d->name(); // safe to call
}
Be careful as this is often seen as a bad practice, and you shouldn't really do it. You don't need the derived type class, try to think in terms of interfaces.

Is it always safe to store store a derived class in base by value?

The following code seem to run without problems.
struct base
{
virtual int foo() {return 0;}
};
struct derriveA : base
{
int foo() {return 1;}
} A;
struct derriveB : base
{
int foo() {return 2;}
} B;
int main()
{
base a = A;
base b = B;
assert(a.foo() != 1);
assert(b.foo() != 2);
}
But is it always safe to store a derived class by value? Is there any case where there is a risk for losing the derived data? Take for example the following code:
base* bb = new base(b);
assert(bb->foo() != 2);
Here i quite clearly tell the compiler only to allocate enough data for "base". However, (for me at-least) the assert is not triggered. Does this mean "bb" actually holds a pointer to deriveB? If so, would that mean that a memory leak occurs if it is deleted as a pointer to "base"?
Compiler: Visual Studio 2012.
But is it always safe to store a derived class by value?
It depends on how you define "safe". In general, however, you do not want to assign an object of a derived class to an object of a base class, because that would cause slicing (as you probably realized). Polymorphism in C++ is realized through pointers or references.
Does this mean "bb" actually holds a pointer to deriveB?
No. The assert fires if the condition is false. In your case, the condition is true, since base::foo() returns 0, which is different from 2.

When is static cast safe when you are using multiple inheritance?

I found myself in a situation where I know what type something is. The Type is one of three (or more) levels of inheritance. I call factory which returns B* however T is either the highest level of a type (if my code knows what it is) or the 2nd level.
Anyways, I did a static_cast in the template which is the wrong thing to do. My question is WHEN can I static cast safely? Is there ever such a time? I did it in this case because I'd rather get compile errors when I accidentally have T as something wacky which (has happened and) dynamic cast ignores (and returns null). However when I know the correct type the pointer is not adjusted causing me to have a bad pointer. I'm not sure why static cast is allowed in this case at all.
When can I use static_cast for down casting safely? Is there ever a situation? Now it seems like it always is wrong to use a static_cast (when the purpose is to down cast)
Ok I figured out how to reproduce it.
#include <iostream>
struct B { virtual void f1(){} };
struct D1 : B {int a;};
struct D2 : B {int a, b; };
struct DD : D1, D2 {};
int main(){
void* cptr = new DD(); //i pass it through a C interface :(
B* a = (B*)cptr;
D2* b = static_cast<D2*>(a); //incorrect ptr
D2* c = dynamic_cast<D2*>(a); //correct ptr
std::cout << a << " " <<b << " " <<c;
}
A cross-cast:
struct Base1 { virtual void f1(); };
struct Base2 { virtual void f2(); };
struct Derived : Base1, Base2 {};
Base1* b1 = new Derived();
Base2* b2 = dynamic_cast<Base2*>(b1);
requires use of dynamic_cast, it cannot be done with static_cast (static_cast should have caused a compile-time error). dynamic_cast will also fail if either base class is not polymorphic (the presence of virtual functions is NOT optional).
See this explanation on MSDN
If Derived has Base as a public (or otherwise accessible) base class, and d is of type Derived*, then static_cast<Base*>(d) is an upcast.
This is always technically safe.
And generally unnecessary, except for cases where you have hiding (shadowing) of method.
Cheers & hth.,
The problem lies with this line:
B* a = (B*)cptr;
If you convert something to a void pointer, you must convert it back to the same type that it was converted from first before doing any other casts. If you have a situation where multiple different types of objects have to go through the same void pointer, then you need to first cast it down to a common type before converting to a void pointer.
int main(){
B *bptr = new DD; // convert to common base first (won't compile in this case)
void* cptr = bptr; // now pass it around as a void pointer
B* a = (B*)cptr; // now back to the type it was converted from
D2* b = static_cast<D2*>(a); // this should be ok now
D2* c = dynamic_cast<D2*>(a); // as well as this
std::cout << a << " " <<b << " " <<c;
}
EDIT:
If you only know that cptr points to some object which is of a type derived from B at the time of the cast, then that isn't enough information to go on. The compiler lets you know that when you try to convert the DD pointer to a B pointer.
What you would have to do is something like this:
int main(){
void* cptr = new DD; // convert to void *
DD* a = (DD*)cptr; // now back to the type it was converted from
D2* b = static_cast<D2*>(a); // this should be ok now, but the cast is unnecessary
D2* c = dynamic_cast<D2*>(a); // as well as this
std::cout << a << " " <<b << " " <<c;
}
but I'm not sure if that is acceptable in your actual usage.
You can safely upcast if you are sure that the object is actually an instance of that class.
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
int main()
{
Base* b = new Derived1;
Derived1* d1 = static_cast<Derived1*>(b); // OK
Derived2* d2 = static_cast<Derived2*>(b); // Run-time error - d isn't an instance of Derived2
}
Just for completeness (knowing that I'm late a little, just for late readers like me...):
static_cast can be applied, if used correctly!
At first, the simple case:
struct D1 { }; // note: no common base class B!
struct D2 { };
struct DD : D1, D2 { };
You can get from D1* to D2* via intermediate downcast to DD*:
D1* d1 = new DD();
D2* d2 = static_cast<DD*>(d1);
The upcast to D2* is implicit then. This is possible even for non-virtual inheritance. But be aware that you need to be 100% sure that d1 really was created as DD when doing the downcast, otherwise you end up in undefined behaviour!
Now the more complex case: Diamond pattern! This is what is presented in the question:
void* cptr = new DD();
B* a = (B*)cptr;
Now this cast is already is dangerous! What actually is implemented here is a reinterpret_cast:
B* a = reinterpret_cast<B*>(cptr);
What you instead want is a simple upcast. Normally, one would not need a cast at all:
B* a = new DD(); //ambigous!
Solely: DD has two inherited instances of B. It would have worked if both D1 and D2 inherited virtually from B (struct D1/2 : virtual B { }; – not to be confused with B/D1/D2 being virtual classes!).
B* b1 = static_cast<D1*>(new DD());
B* b2 = static_cast<D2*>(new DD());
The cast to the respective bases D1 or D2 now makes clear which of the two inherited instances of B shall be pointed to.
You now can get back the respective other instance by down-casting to DD again; due to the diamond pattern, you need an intermediate cast again:
D2* bb1 = static_cast<DD*>(static_cast<D1*>(b1));
D1* bb2 = static_cast<DD*>(static_cast<D2*>(b2));
The very important point about all this matter is: You absolutely need to use, when down-casting, the same diamond edge you used for up-casting!!!
Conclusion: Yes, it is possible using static casts, and it is the only option if the classes involved are not virtual (note: to be differed from virtual inheritance!). But it is just too easy to fail in doing it correctly, sometimes even impossible (e. g. if having stored pointers of base type to arbitrary derived types in a std::vector), so usually, the dynamic_cast solution as presented by Ben is the much safer one (provided virtual data types are available; if so, in the fore-mentioned vector example, it is the only solution!).
A cross cast doesn't need a dynamic_cast at all..
struct Base1 { virtual void f1(); };
struct Base2 { virtual void f2(); };
struct Derived : Base1, Base2 {};
Base1* b1 = new Derived();
// To cast it to a base2 *, cast it first to a derived *
Derived *d = static_cast<Derived *>(b1);
Base2 *b2 = static_cast<Base2 *>(d);

Conversion from void* to the pointer of the base class

I have some hierarchy: base, derived classes and some structure storing user data as void*. That void can store both Base and Derived classes pointers. Main problem that I do not know what is stored there base or derived pointer.
class Base
{
public:
int type;
};
class Derived: public Base
{};
Base* base;//init base pointer
Derived* derived;//init derived pointer
void* base_v = base;
void* derived_v = derived;
//void pointers are correct. They point to base and derived variables.
//try to get type field after converting pointers back
Derived* d_restored = (Derived*)derived_v;//d_restored correct
Base* b_restored = (Base*)base_v;//b_restored correct
Base* d_restored_to_base = (Base*)derived_v;// INCORRECT
How to convert void* to get [type] field for both pointers?
Thanks in advance.
void*'s can only be converted back to their original type. When you store a Derived* in a void*, you can only cast back to Derived*, not Base*.
This is especially noticeable with multiple inheritance, as your derived object might not necessarily be at the same address as your base. If you really need to store things (and retrieve things) with void*, always cast to the base type first, so you have a stable way of getting the object back:
#include <iostream>
struct base { int type; };
struct intruder { int iminyourclassstealingyourbase; };
struct derived : intruder, base {};
int main()
{
derived d; d.type = 5;
void* good = (base*)&d;
void* bad = &d;
base* b1 = (base*)good;
base* b2 = (base*)bad;
std::cout << "good: " << b1->type << "\n";
std::cout << "bad: " << b2->type << "\n";
}
If you then want to go back to the derived type, use a dynamic_cast (or static_cast if you're guaranteed it has to be of the derived type.)
When you use multiple inheritance, the resulting object is internally acting much like a composite, conceptually something like this:
struct Derived {
Base1 b1;
Base2 b2;
};
You will get different addresses for your instance of Derived depending on whether you cast it to Base1 or Base2. So, you can't reliably do what you want to do. You'll need to keep a pointer to one of the involved types, and use dynamic_cast
Alternatively, you could make your own rules - saying that you always store the address of your instance casted to a specific base class, and always cast back to this base class. This is very error-prone, and I'd strongly recommend that you try to store a pointer to a common base class if at all possible.
If you know it's a derived pointer and you want to get a base pointer, you can do this:
Base* d_restored_to_base = (Base*)(Derived*)derived_v;
You will find that the Base* points to a different location than the Derived*, so the intermediary cast is required.
Use dynamic_cast, it can dynamically tell you if the pointer points to a Base object or not.