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 iobjectso 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

Popular posts from this blog

windows - Single EXE to Install Python Standalone Executable for Easy Distribution -

c# - Access objects in UserControl from MainWindow in WPF -

javascript - How to name a jQuery function to make a browser's back button work? -