I've been using multiple inheritance in c++ for quite a long time, but only realised today that this could imply that the pointer addresses could be different when referencing them as one of the subclasses.
For example, if I have:
class ClassA{
public:
int x;
int y;
ClassA(){
cout << "ClassA : " << (unsigned int)this << endl;
}
};
class ClassC{
public:
int cc;
int xx;
ClassC(){
cout << "ClassC : " << (unsigned int)this << endl;
}
};
class ClassB : public ClassC, public ClassA{
public:
int z;
int v;
ClassB(){
cout << "ClassB : " << (unsigned int)this << endl;
}
};
int main(){
ClassB * b = new ClassB();
}
class A and class C have different addresses when printed on the constructor.
Yet, when I try to cast them back to each other, it just works automagically:
ClassA * the_a = (ClassA*)b;
cout << "The A, casted : " << (unsigned int)the_a << endl;
ClassB * the_b = (ClassB*)the_a;
cout << "The B, casted back : " << (unsigned int)the_b << endl;
I suppose this kind of information can be derived by the compiler from the code, but is it safe to assume that this works on all compilers?
Additional Question : is it possible to force the order in which the subclass locations go? For example, if I need classA to be located first (essentially, share the same pointer location) as ClassC which subclasses it, do I just need to put it first in the declaration of subclasses?
Update Okay, looks like it's not possible to force the order. Is it still possible to find out the "root" address of the structure, the start of the address allocated to the subclass, at the superclass level? For example, getting classB's address from ClassA.
That's a perfectly standard use of multiple inheritance, and it will work on any compliant compiler. You should however note that an explicit cast in unnecessary in the first case, and that the 'C style cast' could be replaced by a static_cast in the second.
Is it possible to force the order in which the subclass locations go.
No : the layout is implementation defined, and your code should not depend on this ordering.
Yes, you can ssume that this is safe. A pointer typecast in C++ is guaranteed to correctly adjust the pointer to account for base-to-derived or vice-versa conversions.
That said, you have to be careful not to push the system too far. For example, the compiler won't get this conversion right:
ClassB* b = new ClassB;
ClassC* c = (ClassC*)(void*)b;
This breaks because the cast from C to A get funneled through a void*, and so the information about where the pointer is inside the B object is lost.
Another case where a straight cast won't work is with virtual inheritance. If you want to cast from a derived class to a virtual base or vice-versa, I believe you have to use the dynamic_cast operator to ensure that the cast succeeds.
Yea, a naive implementation for virtual bases is to place at a known location in the derived object a pointer to the virtual base subobject.
If you have multiple virtual bases that's a bit expensive. A better representation (patented by Microsoft I think) uses self-relative offsets. Since these are invariant for each subobject (that is, they don't depend on the object address), they can be stored once in static memory, and all you need is a single pointer to them in each subobject.
Without some such data structure, cross casts would not work. You can cross cast from a virtual base A to a virtual base B inside the virtual base A even though B subobject isn't visible (provided only the two bases have a shared virtual base X if I recall correctly). That's pretty hairy navigation when you think about it: the navigation goes via the shape descriptor of the most derived class (which can see both A and B).
What's even more hairy is that the structure so represented is required "by law of the Standard" to change dynamically during construction and destruction, which is why construction and destruction of complex objects is slow. Once they're made, however, method calls, even cross calls, are quite fast.
Related
I've been using multiple inheritance in c++ for quite a long time, but only realised today that this could imply that the pointer addresses could be different when referencing them as one of the subclasses.
For example, if I have:
class ClassA{
public:
int x;
int y;
ClassA(){
cout << "ClassA : " << (unsigned int)this << endl;
}
};
class ClassC{
public:
int cc;
int xx;
ClassC(){
cout << "ClassC : " << (unsigned int)this << endl;
}
};
class ClassB : public ClassC, public ClassA{
public:
int z;
int v;
ClassB(){
cout << "ClassB : " << (unsigned int)this << endl;
}
};
int main(){
ClassB * b = new ClassB();
}
class A and class C have different addresses when printed on the constructor.
Yet, when I try to cast them back to each other, it just works automagically:
ClassA * the_a = (ClassA*)b;
cout << "The A, casted : " << (unsigned int)the_a << endl;
ClassB * the_b = (ClassB*)the_a;
cout << "The B, casted back : " << (unsigned int)the_b << endl;
I suppose this kind of information can be derived by the compiler from the code, but is it safe to assume that this works on all compilers?
Additional Question : is it possible to force the order in which the subclass locations go? For example, if I need classA to be located first (essentially, share the same pointer location) as ClassC which subclasses it, do I just need to put it first in the declaration of subclasses?
Update Okay, looks like it's not possible to force the order. Is it still possible to find out the "root" address of the structure, the start of the address allocated to the subclass, at the superclass level? For example, getting classB's address from ClassA.
That's a perfectly standard use of multiple inheritance, and it will work on any compliant compiler. You should however note that an explicit cast in unnecessary in the first case, and that the 'C style cast' could be replaced by a static_cast in the second.
Is it possible to force the order in which the subclass locations go.
No : the layout is implementation defined, and your code should not depend on this ordering.
Yes, you can ssume that this is safe. A pointer typecast in C++ is guaranteed to correctly adjust the pointer to account for base-to-derived or vice-versa conversions.
That said, you have to be careful not to push the system too far. For example, the compiler won't get this conversion right:
ClassB* b = new ClassB;
ClassC* c = (ClassC*)(void*)b;
This breaks because the cast from C to A get funneled through a void*, and so the information about where the pointer is inside the B object is lost.
Another case where a straight cast won't work is with virtual inheritance. If you want to cast from a derived class to a virtual base or vice-versa, I believe you have to use the dynamic_cast operator to ensure that the cast succeeds.
Yea, a naive implementation for virtual bases is to place at a known location in the derived object a pointer to the virtual base subobject.
If you have multiple virtual bases that's a bit expensive. A better representation (patented by Microsoft I think) uses self-relative offsets. Since these are invariant for each subobject (that is, they don't depend on the object address), they can be stored once in static memory, and all you need is a single pointer to them in each subobject.
Without some such data structure, cross casts would not work. You can cross cast from a virtual base A to a virtual base B inside the virtual base A even though B subobject isn't visible (provided only the two bases have a shared virtual base X if I recall correctly). That's pretty hairy navigation when you think about it: the navigation goes via the shape descriptor of the most derived class (which can see both A and B).
What's even more hairy is that the structure so represented is required "by law of the Standard" to change dynamically during construction and destruction, which is why construction and destruction of complex objects is slow. Once they're made, however, method calls, even cross calls, are quite fast.
Well so i have been trying to understand OOP concepts through C++ , however i am not able to get some parts of virtual destructors.
I have written a small snippet :
class A{
int x;
public:
virtual void show(){
cout << " In A\n";
}
virtual ~A(){
cout << "~A\n";
};
};
class B: public A{
int y;
public:
virtual void show(){
cout << " In B\n";
}
virtual ~B(){
cout << "~B\n";
};
};
class C: public A{
int z;
public:
virtual void show(){
cout << " In C\n";
}
virtual ~C(){
cout << "~C\n";
};
};
class E: public A{
int z;
public:
virtual void show(){
cout << " In E\n";
}
virtual ~E(){
cout << "~E\n";
};
};
class D: public B , public C , public E{
int z1;
public:
virtual void show(){
cout << " In D\n";
}
virtual ~D(){
cout << "~D\n";
};
};
signed main(){
// A * a = new A();
// B *b = new B();
D *d = new D();
B *b = d;
C *c = d;
E * e = d;
A * a = new A();
cout << d << "\n";
cout << b << "\n";
cout << c << "\n";
cout << e << "\n";
delete b;
// a -> show();
}
On running the code , i get the result as :
0x7f8c5e500000
0x7f8c5e500000
0x7f8c5e500018
0x7f8c5e500030
~D
~E
~A
~C
~A
~B
~A
Now three questions :
According to the wikipedia article , virtual_table , it was referred that object c gets an address +8 bytes than that of d and b , what happens in case of e.
When i call delete b instead of delete d , also get the same order sequence of virtual destructors , so why is the derived class destructor called
The virtual destructors are called only when i delete an object , then how are the vtable and vpointers gets deleted when the program ends ( when i run the code without the delete d the execution just stops without printing anything ).
Your questions in order:
(1) Yes, pointers to bases refering to objects of derived classes with multiple inheritance may change their numerical value compared to a pointer to the most derived type. The reason is that the base class is a part of the derived class, much like a member, residing at an offset. Only for the first derived class in multi-inheritance this offset can be 0. This is the reason why such pointers cannot be cast with a simple reinterpret_cast().
(2) b points to an E which also is-an A.
Exactly that is what being virtual means for a member function: The code generated by the compiler inspects the object pointed to at run time and calls the function defined for the actual type of the object (which is an E), as opposed to the type of the expression used to access that object (which is B). The type of the expression is fully determined at compile time; the type of the actual complete object is not.
If you do not declare a destructor virtual the program may behave as you perhaps expected: The compiler will create code which simply calls the function defined for the type of the expression (for B), without any run-time look-ups. Non-virtual member function calls are slightly more efficient; but in the case of destructors as in your case the behavior is undefined when destroying through a base class expression. If your destructor is public it should be virtual because this scenario could happen.
Herb Sutter has written an article about virtual functions including virtual destructors that's worth reading.
(3) The memory, including dynamically allocated memory, is released and made available again for other uses by modern standard operating systems when the program has exited. (This may not be the case in old operating systems or freestanding implementations, if they offer dynamic allocation.) Destructors of dynamically allocated objects, however, will not be called, which may be a problem if they hold resources like database or network connections which should better be released.
Regarding the addresses of the objects. As already explained in another answer this is compiler dependent. However it can still be explained.
Address of objects in Multiple Inheritance
(a possible compiler implementation)
Here is a possible memory diagram, assuming that the pointer to the virtual table is 8 bytes and int is 4 bytes.
Class D first has its pointer to virtual table (vtbl_ptr or vptr) then comes class B without its own vtbl_ptr, as it can share the same vtbl as D.
Classes C and E must come with their own embedded vtbl_ptr. It will point to the vtbl of D (almost..., there is a thunk issue to handle but let's ignore it, you can read about thunk in the links below but this doesn't affect the need for additional vtbl_ptr).
The additional vptr for each additional base class is required so when we look at C or E, the position of the vptr is always at the same location, i.e. at the top of the object, regardless if it is actually a concrete C or it is a D that is held as C. And the same for E and any other base class that is not the first inherited base.
The addresses that we may see according to the above:
D d; // sitting at some address X
B* b = &d; // same address
C* c = &d; // jumps over vtbl_ptr (8 bytes) + B without vtbl_ptr (8 bytes)
// thus X + 16 -- or X + 10 in hexa
E* e = &d; // jumps in addition over C part including vtbl_ptr (16 bytes)
// thus X + 32 -- or X + 20 in hexa
Note that the math for the addresses that appear in the question might be a bit different, as said things are compiler dependent. Size of int may be different, padding might be different and the way to arrange the vtbl and vptr is also compiler dependent.
To read more about object layout and address calulations, see:
C++: Under the Hood by Jan Gray (old but still relevant)
And the following SO entries on the subject:
Object layout in case of virtual functions and multiple inheritance
Understanding virtual table in multiple inheritance
According to the wikipedia article , virtual_table , it was referred that object c gets an address +8 bytes than that of d and b , what happens in case of e.
Addresses are often compiler-dependent, and hence pretty dicey. I wouldn't rely on them being any particular value.
When i call delete b instead of delete d , also get the same order sequence of virtual destructors , so why is the derived class destructor called
The type of the pointer doesn't matter. The underlying object was created with new D() so those are the destructors that get called. This is because it might be difficult to delete objects properly otherwise -- if you have a factory that creates various subclasses, how would you know which type to delete it as?
(What's actually going on here is that (pointers to) the destructors are stored in the object's vtable.)
The virtual destructors are called only when i delete an object , then how are the vtable and vpointers gets deleted when the program ends ( when i run the code without the delete d the execution just stops without printing anything ).
If you never delete something, it never gets cleaned up. The program ends without freeing that memory from the heap. This is a "memory leak". When the program ends, the OS cleans up the whole program's heap in one go (without caring what's in it).
When I do sizeof in c++, will I be sure to get the "whole object"? I am asking because I am about to copy objects to other areas of memory using memcpy (probably a stupid idea from the start, right?).
What I am worried about is that I may not get the whole object, but only the parts belonging to the class it is casted to right now. Does it make any sense or am I being confused?
EDIT Examples
class A{ public: int a = 123; };
class B: public A{ public: int b = 321; };
class C : public B{ public: int c = 333; };
C c_ = C();
B b_ = C();
A a_ = C();
std::cout << sizeof(a_) << " , " << sizeof(b_) << " , " << sizeof(c_) << std::endl;
Seems to give me 4,8,12.
I guess I would need to do dynamic casting to figure out how to get the "whole" object which I constructed as a "C" class in each case?
sizeof will always return the static size of your object. Notice that in your example it will coincide with the true object size, as there is no polymorphism; when you do
A a = B();
a is of type A - you just happened to initialize a new A object with a new B object, which results in slicing (a gets initialized with the fields of B() that are common with A).
A better example would be:
B b;
A *a = &b;
In this case, *a will indeed be of dynamic type B, but sizeof(*a) will still return sizeof(A), not sizeof(B).
There are several ways to obtain the dynamic size of an object:
save it into a field at construction time;
in theory, you could define a virtual method that does return sizeof(*this); and redefine it in all derived classes.
That being said, this last method won't be particularly useful, as doing memcpy of non-trivial types such as polymorphic classes is undefined behavior (and so even the first method as well, as I imagine that you'll want to do this with polymorphic types).
The common approach to the problem of copying polymorphic classes is to accept the fact that they'll have to live in the heap and define clone() method that does virtual A * clone() {return new B(*this);} (where B is the derived class) in each derived class, and invoke clone() whenever you need a copy.
Mind you, there are subtler tricks you can pull; once I had a class hierarchy which had a virtual method dispatching to the placement new for each derived class and one for the destructor, but you really have to know what you are doing (in my case I was invoking them over a union containing an instance for each derived class, so size and alignment was not a problem).
I was researching how to get the memory offset of a member to a class in C++ and came across this on wikipedia:
In C++ code, you can not use offsetof to access members of structures or classes that are not Plain Old Data Structures.
I tried it out and it seems to work fine.
class Foo
{
private:
int z;
int func() {cout << "this is just filler" << endl; return 0;}
public:
int x;
int y;
Foo* f;
bool returnTrue() { return false; }
};
int main()
{
cout << offsetof(Foo, x) << " " << offsetof(Foo, y) << " " << offsetof(Foo, f);
return 0;
}
I got a few warnings, but it compiled and when run it gave reasonable output:
Laptop:test alex$ ./test
4 8 12
I think I'm either misunderstanding what a POD data structure is or I'm missing some other piece of the puzzle. I don't see what the problem is.
Bluehorn's answer is correct, but for me it doesn't explain the reason for the problem in simplest terms. The way I understand it is as follows:
If NonPOD is a non-POD class, then when you do:
NonPOD np;
np.field;
the compiler does not necessarily access the field by adding some offset to the base pointer and dereferencing. For a POD class, the C++ Standard constrains it to do that(or something equivalent), but for a non-POD class it does not. The compiler might instead read a pointer out of the object, add an offset to that value to give the storage location of the field, and then dereference. This is a common mechanism with virtual inheritance if the field is a member of a virtual base of NonPOD. But it is not restricted to that case. The compiler can do pretty much anything it likes. It could call a hidden compiler-generated virtual member function if it wants.
In the complex cases, it is obviously not possible to represent the location of the field as an integer offset. So offsetof is not valid on non-POD classes.
In cases where your compiler just so happens to store the object in a simple way (such as single inheritance, and normally even non-virtual multiple inheritance, and normally fields defined right in the class that you're referencing the object by as opposed to in some base class), then it will just so happen to work. There are probably cases which just so happen to work on every single compiler there is. This doesn't make it valid.
Appendix: how does virtual inheritance work?
With simple inheritance, if B is derived from A, the usual implementation is that a pointer to B is just a pointer to A, with B's additional data stuck on the end:
A* ---> field of A <--- B*
field of A
field of B
With simple multiple inheritance, you generally assume that B's base classes (call 'em A1 and A2) are arranged in some order peculiar to B. But the same trick with the pointers can't work:
A1* ---> field of A1
field of A1
A2* ---> field of A2
field of A2
A1 and A2 "know" nothing about the fact that they're both base classes of B. So if you cast a B* to A1*, it has to point to the fields of A1, and if you cast it to A2* it has to point to the fields of A2. The pointer conversion operator applies an offset. So you might end up with this:
A1* ---> field of A1 <---- B*
field of A1
A2* ---> field of A2
field of A2
field of B
field of B
Then casting a B* to A1* doesn't change the pointer value, but casting it to A2* adds sizeof(A1) bytes. This is the "other" reason why, in the absence of a virtual destructor, deleting B through a pointer to A2 goes wrong. It doesn't just fail to call the destructor of B and A1, it doesn't even free the right address.
Anyway, B "knows" where all its base classes are, they're always stored at the same offsets. So in this arrangement offsetof would still work. The standard doesn't require implementations to do multiple inheritance this way, but they often do (or something like it). So offsetof might work in this case on your implementation, but it is not guaranteed to.
Now, what about virtual inheritance? Suppose B1 and B2 both have A as a virtual base. This makes them single-inheritance classes, so you might think that the first trick will work again:
A* ---> field of A <--- B1* A* ---> field of A <--- B2*
field of A field of A
field of B1 field of B2
But hang on. What happens when C derives (non-virtually, for simplicity) from both B1 and B2? C must only contain 1 copy of the fields of A. Those fields can't immediately precede the fields of B1, and also immediately precede the fields of B2. We're in trouble.
So what implementations might do instead is:
// an instance of B1 looks like this, and B2 similar
A* ---> field of A
field of A
B1* ---> pointer to A
field of B1
Although I've indicated B1* pointing to the first part of the object after the A subobject, I suspect (without bothering to check) the actual address won't be there, it'll be the start of A. It's just that unlike simple inheritance, the offsets between the actual address in the pointer, and the address I've indicated in the diagram, will never be used unless the compiler is certain of the dynamic type of the object. Instead, it will always go through the meta-information to reach A correctly. So my diagrams will point there, since that offset will always be applied for the uses we're interested in.
The "pointer" to A could be a pointer or an offset, it doesn't really matter. In an instance of B1, created as a B1, it points to (char*)this - sizeof(A), and the same in an instance of B2. But if we create a C, it can look like this:
A* ---> field of A
field of A
B1* ---> pointer to A // points to (char*)(this) - sizeof(A) as before
field of B1
B2* ---> pointer to A // points to (char*)(this) - sizeof(A) - sizeof(B1)
field of B2
C* ----> pointer to A // points to (char*)(this) - sizeof(A) - sizeof(B1) - sizeof(B2)
field of C
field of C
So to access a field of A using a pointer or reference to B2 requires more than just applying an offset. We must read the "pointer to A" field of B2, follow it, and only then apply an offset, because depending what class B2 is a base of, that pointer will have different values. There is no such thing as offsetof(B2,field of A): there can't be. offsetof will never work with virtual inheritance, on any implementation.
Short answer: offsetof is a feature that is only in the C++ standard for legacy C compatibility. Therefore it is basically restricted to the stuff than can be done in C. C++ supports only what it must for C compatibility.
As offsetof is basically a hack (implemented as macro) that relies on the simple memory-model supporting C, it would take a lot of freedom away from C++ compiler implementors how to organize class instance layout.
The effect is that offsetof will often work (depending on source code and compiler used) in C++ even where not backed by the standard - except where it doesn't. So you should be very careful with offsetof usage in C++, especially since I do not know a single compiler that will generate a warning for non-POD use... Modern GCC and Clang will emit a warning if offsetof is used outside the standard (-Winvalid-offsetof).
Edit: As you asked for example, the following might clarify the problem:
#include <iostream>
using namespace std;
struct A { int a; };
struct B : public virtual A { int b; };
struct C : public virtual A { int c; };
struct D : public B, public C { int d; };
#define offset_d(i,f) (long(&(i)->f) - long(i))
#define offset_s(t,f) offset_d((t*)1000, f)
#define dyn(inst,field) {\
cout << "Dynamic offset of " #field " in " #inst ": "; \
cout << offset_d(&i##inst, field) << endl; }
#define stat(type,field) {\
cout << "Static offset of " #field " in " #type ": "; \
cout.flush(); \
cout << offset_s(type, field) << endl; }
int main() {
A iA; B iB; C iC; D iD;
dyn(A, a); dyn(B, a); dyn(C, a); dyn(D, a);
stat(A, a); stat(B, a); stat(C, a); stat(D, a);
return 0;
}
This will crash when trying to locate the field a inside type B statically, while it works when an instance is available. This is because of the virtual inheritance, where the location of the base class is stored into a lookup table.
While this is a contrived example, an implementation could use a lookup table also to find the public, protected and private sections of a class instance. Or make the lookup completely dynamic (use a hash table for fields), etc.
The standard just leaves all possibilities open by restricting offsetof to POD (IOW: no way to use a hash table for POD structs... :)
Just another note: I had to reimplement offsetof (here: offset_s) for this example as GCC actually errors out when I call offsetof for a field of a virtual base class.
In general, when you ask "why is something undefined", the answer is "because the standard says so". Usually, the rational is along one or more reasons like:
it is difficult to detect statically in which case you are.
corner cases are difficult to define and nobody took the pain of defining special cases;
its use is mostly covered by other features;
existing practices at the time of standardization varied and breaking existing implementation and programs depending on them was deemed more harmful that standardization.
Back to offsetof, the second reason is probably a dominant one. If you look at C++0X, where the standard was previously using POD, it is now using "standard layout", "layout compatible", "POD" allowing more refined cases. And offsetof now needs "standard layout" classes, which are the cases where the committee didn't want to force a layout.
You have also to consider the common use of offsetof(), which is to get the value of a field when you have a void* pointer to the object. Multiple inheritance -- virtual or not -- is problematic for that use.
I think your class fits the c++0x definition of a POD. g++ has implemented some of c++0x in their latest releases. I think that VS2008 also has some c++0x bits in it.
From wikipedia's c++0x article
C++0x will relax several rules with regard to the POD definition.
A class/struct is considered a POD if it is trivial, standard-layout, and
if all of its non-static members are
PODs.
A trivial class or struct is defined
as one that:
Has a trivial default constructor. This may use the default
constructor syntax (SomeConstructor()
= default;).
Has a trivial copy constructor, which may use the default syntax.
Has a trivial copy assignment operator, which may use the default
syntax.
Has a trivial destructor, which must not be virtual.
A standard-layout class or struct is
defined as one that:
Has only non-static data members that are of standard-layout type
Has the same access control (public, private, protected) for all
non-static members
Has no virtual functions
Has no virtual base classes
Has only base classes that are of standard-layout type
Has no base classes of the same type as the first defined non-static
member
Either has no base classes with non-static members, or has no
non-static data members in the most
derived class and at most one base
class with non-static members. In
essence, there may be only one class
in this class's hierarchy that has
non-static members.
For the definition of POD data structure,here you go with the explanation [ already posted in another post in Stack Overflow ]
What are POD types in C++?
Now, coming to your code, it is working fine as expected. This is because, you are trying to find the offsetof(), for the public members of your class, which is valid.
Please let me know, the correct question, if my viewpoint above, doesnot clarify your doubt.
This works every time and its the most portable version to be used in both c and c++
#define offset_start(s) s
#define offset_end(e) e
#define relative_offset(obj, start, end) ((int64_t)&obj->offset_end(end)-(int64_t)&obj->offset_start(start))
struct Test {
int a;
double b;
Test* c;
long d;
}
int main() {
Test t;
cout << "a " << relative_offset((&t), a, a) << endl;
cout << "b " << relative_offset((&t), a, b) << endl;
cout << "c " << relative_offset((&t), a, c) << endl;
cout << "d " << relative_offset((&t), a, d) << endl;
return 0;
}
The above code simply requires you to hold an instance of some object be it a struct or a class. you then need to pass a pointer reference to the class or struct to gain access to its fields. To make sure you get the right offset never set the "start" field to be under the "end" field. We use the compiler to figure out what the address offset is at run-time.
This allows you to not have to worry about the problems with compiler padding data, etc.
If you add, for instance, a virtual empty destructor:
virtual ~Foo() {}
Your class will become "polymorphic", i.e. it will have a hidden member field which is a pointer to a "vtable" that contains pointers to virtual functions.
Due to the hidden member field, the size of an object, and offset of members, will not be trivial. Thus, you should get trouble using offsetof.
I bet you compile this with VC++. Now try it with g++, and see how it works...
Long story short, it's undefined, but some compilers may allow it. Others do not. In any case, it's non-portable.
Works for me
#define get_offset(type, member) ((size_t)(&((type*)(1))->member)-1)
#define get_container(ptr, type, member) ((type *)((char *)(ptr) - get_offset(type, member)))
In C++ you can get the relative offset like this:
class A {
public:
int i;
};
class B : public A {
public:
int i;
};
void test()
{
printf("%p, %p\n", &A::i, &B::i); // edit: changed %x to %p
}
This seems to work fine for me:
#define myOffset(Class,Member) ({Class o; (size_t)&(o.Member) - (size_t)&o;})
Given the following class structure:
class Base
{
virtual void outputMessage() { cout << "Base message!"; }
};
class Derived : public Base
{
virtual void outputMessage() { cout << "Derived message!"; }
}
.. and this code snippet:
Base baseObj;
Derived* convertedObj = (Derived*) &baseObj;
convertedObj->outputMessage();
.. the output will be "Base message!".
Is there any way to cast or manipulate the object to make Derived's version of the outputMessage method to be called polymorphically?
Edit: I will attempt to show the reason why I'm after this:
I am writing migration tools that hook into our main system. For this reason, I need to get access to protected member methods, or customise existing virtual methods. The former I can do by defining a derived class and casting objects to it, to call methods statically. What I can't do is change the behaviour for methods which I do not call statically (ie methods that are called elsewhere in the codebase).
I have also tried creating objects of the derived class directly, but this causes issues in other parts of the system due to the manipulation of the objects passed through the constructor.
No, virtual functions operate on the actual types of the object being pointed to, which in your case is just a simple Base.
Actually, with the down-casting, you're entering undefined-behaviour land here. This can blow off like a bomb with multiple inheritance, where the vtable in the derived class isn't at the same offset as the vtable in the base class.
No Standard-compliant solution
What you're trying to do isn't possible using behaviours guaranteed by the C++ Standard.
If you really MUST do this as a short-term measure to assist your migration, don't depend on it in production, and can adequately verify the behaviour, you could experiment as illustrated below.
Discussion of your attempt
What I'm showing is that you're taking the wrong approach: simply casting a pointer-to-base to a pointer-to-derived doesn't alter the object's vtable pointer.
Deriving a plausible hack
Addressing that, the naive approach is to reconstruct the object in place as a derived object ("placement" new), but this doesn't work either - it will reinitialise the base class members.
What you can possibly do is create a non-derived object that has no data members but the same virtual dispatch table entries (i.e. same virtual functions, same accessibility private/protected/public, same order).
More warnings and caveats
It may work (as it does on my Linux box), but use it at your own risk (I suggest not on production systems).
Further warning: this can only intercept virtual dispatch, and virtual functions can sometimes be dispatched statically when the compiler knows the types at compile time.
~/dev cat hack_vtable.cc
// change vtable of existing object to intercept virtual dispatch...
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f()\n"; }
std::string s_;
};
struct D : B
{
virtual void f() { std::cout << "D::f()\n"; }
};
struct E
{
virtual void f() { std::cout << "E::f()\n"; }
};
int main()
{
B* p = new B();
p->s_ = "hello";
new (p) D(); // WARNING: reconstructs B members
p->f();
std::cout << '\'' << p->s_ << "'\n"; // no longer "hello"
p->s_ = "world";
new (p) E();
p->f(); // correctly calls E::f()
std::cout << '\'' << p->s_ << "'\n"; // still "world"
}
~/dev try hack_vtable
make: `hack_vtable' is up to date.
D::f()
''
E::f()
'world'
Well, even if you're casting your Base object as a Derived one, internally, it's still a Base object: the vftable of your object (the actual map of functions to RAM pointers) is not updated.
I don't think there is any way to do what you want to do and I don't understand why you'd like to do it.
In this question downcast problem in c++ Robs answer should also be the answer to your problem.
Not at least in legal way. To call Derived class function, you need to have Derived object being referred.