#include <iostream>
#include <vector>
usingnamespace std;
class Super1
{
// public:
// virtual void notify () = 0;
};
class Super2
{
vector<Super1*> v;
public:
void m (Super1* ptr) { cout << (this) << endl; }
};
class Sub : public Super1, public Super2
{
};
class Test : public Sub
{
string s;
int at1;
int at2;
public:
Test (constchar* s) { this->s = s; }
//void notify () {}
};
int main ()
{
Test obj("DDD");
cout << (&obj) << endl;
obj.m (&obj);
return ( 0 );
}
is, for example:
0xbfd0a2e8
0xbfd0a2e8
Nice. It's correct. Both addresses are equal.
But, if I uncomment those 3 commented lines, adding the polymorphic abstract method and its implementation in the "Test" sub-class, I get, for example, the output:
0xbffeb164
0xbffeb168
This is wrong! The address pointed by "this" is four bytes ahead the other.
Does anyone have an idea?
Thanks!
P.S.: Sorry about any english erros, I'm from Brazil!
Test
{
Sub
{
Super1
{
// vtable
}
Super2
{
vector<Super1*> v;
}
}
string s;
int at1;
int at2;
}
Test inherits from Sub so all the data members of Sub will be put at the start of Test. Same with Sub. Super1 doesn't have any data so Super2 will also be placed at the beginning of Sub (which is the beginning of Test). This means that Super2 and Test will be on the same memory location.
When you add the virtual function to Super1, a vtable is added to Super1. The size of the vtable is often the same as the size of a pointer. This means that Super2 will have to be placed after Super1 and that is why you see that the pointers are different.
Note that this is implementation details and is not guaranteed by the C++ standard.
Thanks! I guess I understand. So, if I'm supposing that the "m" method could be called by a "Test" object passing the pointer of the object itself; and I would like do throw an exception in this case, I certainly should make the following comparison:
Oh, I just saw that m is in Super2 and if is not a subclass of Super1 so that wont work. And +/- the pointer value might not work on a different compiler.
Thinking.
Does this work? Because Super1 & Super2 are unrelated, they could never have the same address. And when you cast to Sub, can you get that to be true in the m function?
An object of type Sub has an anonymous base class object of type Super1 and another anonymous base class object of type Super2. These are at two different objects at two different offsets within Sub; therefore the base class objects will have two different addresses.
Unless a base class is empty and the compiler applies the 'empty base class optimization'.
A<1>* this == 0x7fff5fbff340
A<2>* this == 0x7fff5fbff340
A<3>* this == 0x7fff5fbff340
A<4>* this == 0x7fff5fbff340
A<5>* this == 0x7fff5fbff340
A<6>* this == 0x7fff5fbff340
A<7>* this == 0x7fff5fbff340
A<8>* this == 0x7fff5fbff340
A<1>* this == 0x7fff5fbff3d0
Why are the first 8 As are the same address?
EDIT: Because the lowest base class is the address for all other classes derived classes?
Like in the example above C<8>'s address is 0x7fff5fbff340.
Very interesting code. Thanks for the example.
The anonymous base class sub-object can be at an offset of zero bytes within the derived class object.
In fact, every self-respecting compiler will try to place a base class sub object at a zero offset - pointer/reference conversions are then trivial and incur no run-time overhead (check for nullptr, if not null add/subtract the offset).
If there is more than one base class, only one of the base class sub-objects can have an offset of zero.
matheuscscp, avoid c-style cast in C++.
Here you should prefer:
if ( static_cast<Super2*>(ptr) == this )
static_cast job is to convert types compatibles, for example an int to a float or a pointer to another pointer of the same hierarchy. It will do all the offset stuff for you.
C-style cast might work but better use c++ tools
So, based on JLBorges's post with the templates, when you have multiple inheritances the two parent classes will never have the same this pointer unless they inherit from the same base class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// A B
// \ /
// C
// ---------> Will never be true?
static_cast<A*>(&C) == static_cast<B*>(&C)
//
// A
// / \
// B C
// \ /
// D
// ---------> Could be true?
static_cast<B*>(&D) == static_cast<C*>(&D)
thank you aquaz, I read about the casting operators and I could solve this problem. it didn't work with static_cast probably because Super1 & Super2 are unrelated, so I had to use dynamic_cast. I can't avoid the overhead, but I guess it won't be a problem...