Virtual inheritance applies

The following code fails (access violation error) because I used virtual inheritance.
AFAIK virtual inheritance solves the Diamond problem by forcing the use of a single instance of the class. In this case, the class Derivedinherits only one instance IObject, so there should not be any problems, but it fails.

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 I remove the virtual keyword here problem is 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;
}
+4
source share
4 answers

, : Derived* -> void* -> IObject* - undefined , C ++. , void* C - .

, , , void* T -> void* -> T: . , Derived* -> IObject* -> void* -> IObject*.


, virtual , , ​​ ( ). ( Itanium ABI).

:

struct Base { int a; };
struct Derived: Base { int b; };
struct SuperDerived: Derived { int c; };

+---+---+
| a | b |
+---+---+
^~~~~~~~~ Derived
    ^~~~~ Derived specific
^~~~~         Base

+---+---+---+
| a | b | c |
+---+---+---+
^~~~~~~~~~~~~ SuperDerived
        ^~~~~ SuperDerived specific
^~~~~~~~~     Derived
^~~~~         Base

&derived == &base &superderived == &derived ( : , , ).

struct Base1 { int a; };
struct Base2 { int b; };
struct Derived: Base1, Base2 { int c; };

+---+---+---+
| a | b | c |
+---+---+---+
^~~~~~~~~~~~~ Derived
        ^~~~~ Derived specific
    ^~~~~     Base2
^~~~~         Base1

&derived == &base1, &derived != &base2, , , .

, , push virtual inheritance :

struct Object { int a; };
struct Base1: virtual Object { int b; };
struct Base2: virtual Object { int c; };
struct Derived: Base1, Base2 { int d; };

+---+---+
| b | a |
+---+---+
^~~~~~~~~ Complete Base1
^~~~~     Base1 specific
    ^~~~~ Object

+---+---+
| c | a |
+---+---+
^~~~~~~~~ Complete Base2
^~~~~     Base2 specific
    ^~~~~ Object

+---+---+---+---+
| b | c | d | a |
+---+---+---+---+
^~~~~~~~~~~~~~~~~ Complete Derived
        ^~~~~     Derived specific
^~~~~             Incomplete Base1
    ^~~~~         Incomplete Base2
            ^~~~~ Object

, . , , , ( ) , , runtime, Object .

, , &base1 != &object, &base2 != &object &derived != &object, Object .

++-, , ( ) , .

: ++ , , , , static_cast<Base1*>(&object) , dynamic_cast.

+3

- void * ( ). , void *, - undefined, .

++ , . c style ( void *) , IObject ( barak manos).

( void *):

#include <iostream>

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
{
public:
    Derived() { val = 2; }
};

int getVal( IObject* ptr ) 
{
    return ptr->getType();
}

int main()
{
    IObject* ptr = new Derived();
    std::cout << getVal(ptr) << std::endl;
    return 0;
}
+3

:

void* ptr = new Derived();
IObject* ptr1 = (IObject*)ptr;
IObject* ptr2 = new Derived();
IObject* ptr3 = new Derived();

IObject , , :

enter image description here

Derived - ( ), ( V-Table) . Visual Studio __vfptr.

, ptr2->__vfptr ptr3->__vfptr 0x01236834, V- . - 0x012310f0, Base::getType.

, ptr1->__vfptr 0x0123683C. " " 0x00000000, , , , , , , .

+3
source

Failure caused by reinterpret_cast.

    void* ptr = new Derived();

in fact

void* ptr = reinterpret_cast<void*>(new Derived());

When you do this, ptr does not know what it is pointing to. When you do

return ((IObject*)ptr)->getType();

it means

return (reinterpret_cast<IObject*>(ptr))->getType();

This calls IObject :: getType, which is undefined: hence the failure. To get around this, use IObject * instead of void *

IObject* ptr = new Derived();
...
int getval(IObject* ptr)
{
    return ptr->getType();
}
+1
source

Source: https://habr.com/ru/post/1536423/


All Articles