c++ - Virtual inheritance crashes application -
the following code crashes (access violation error) because used virtual inheritance.
afaik virtual inheritance solves diamond problem forcing use of single instance of class. in case derived
class inherits 1 instance of iobject
so there should no problem, crashes.
class iobject { public: virtual int gettype()=0; }; class base : public iobject { protected: int val; public: base() { val = 1; } virtual int gettype(); }; int base::gettype() { return val; } class derived : public virtual base //if remove virtual keyword here problem solved. { public: derived() { val = 2; } }; int getval( void* ptr ) { return ((iobject*)ptr)->gettype(); } int main() { void* ptr = new derived(); cout << getval(ptr) << endl; return 0; }
the problem chain of casts incorrect: derived* -> void* -> iobject*
undefined behavior resulting mixing c , c++ concepts. more specifically, rules around void*
inherited c without adaptation objects , hierarchy.
the solution, therefore, make sure cycle through void*
t -> void* -> t
cycle: through same type. thus, in situation, need derived* -> iobject* -> void* -> iobject*
.
to understand why virtual
inheritance causes issue, have understand specifics of how represented concretely (which implementation-defined). let's have @ examples of possible in-memory representations (loosely based on itanium abi).
a linear non-virtual hierarchy implemented if composition:
struct base { int a; }; struct derived: base { int b; }; struct superderived: derived { int c; }; +---+---+ | | b | +---+---+ ^~~~~~~~~ derived ^~~~~ derived specific ^~~~~ base +---+---+---+ | | b | c | +---+---+---+ ^~~~~~~~~~~~~ superderived ^~~~~ superderived specific ^~~~~~~~~ derived ^~~~~ base
in case, &derived == &base
, &superderived == &derived
in general (note: if 1 layer not have virtual table , next layer does, falls off roof).
a hierarchy multiple bases
struct base1 { int a; }; struct base2 { int b; }; struct derived: base1, base2 { int c; }; +---+---+---+ | | b | c | +---+---+---+ ^~~~~~~~~~~~~ derived ^~~~~ derived specific ^~~~~ base2 ^~~~~ base1
in case, &derived == &base1
&derived != &base2
, note base class not have same address derived class.
and finally, let's push virtual inheritance in:
struct object { int a; }; struct base1: virtual object { int b; }; struct base2: virtual object { int c; }; struct derived: base1, base2 { int d; }; +---+---+ | b | | +---+---+ ^~~~~~~~~ complete base1 ^~~~~ base1 specific ^~~~~ object +---+---+ | c | | +---+---+ ^~~~~~~~~ complete base2 ^~~~~ base2 specific ^~~~~ object +---+---+---+---+ | b | c | d | | +---+---+---+---+ ^~~~~~~~~~~~~~~~~ complete derived ^~~~~ derived specific ^~~~~ incomplete base1 ^~~~~ incomplete base2 ^~~~~ object
the challenge here single instance of virtual base should shared between potential bases. since complete object knows bases involved, simple choice let complete object responsible placement of virtual base (which places @ tail) , have virtual table provide machinery navigate, @ runtime, object
derived class.
however, note in case of how our design &base1 != &object
, &base2 != &object
, &derived != &object
because object
placed @ tail.
that why important perform casts using c++ machinery knows how statically or dynamically (depending on situation) compute pointer adjustment necessary when going 1 base another.
note: c++ machinery knows whether computation static or dynamic , example static_cast<base1*>(&object)
compile-time error, dynamic_cast
necessary here.
Comments
Post a Comment