0

I have a struct with several (virtual) bases. From one of these bases' constructor I static_cast to the most derived type, and from there try access a member of another base (which has been initialised before). The adress doesn't match with the result when accessing from the most derived struct's constructor directly. Weirdly (at least to me) the problem only appears if another base (the direct base of the struct where the static_cast originates)is empty.

I recreated the problem in the below example (tested with GNU 9.3.0 on ubuntu linux)

#include <iostream>
#include <string>

/* --: virtual inheritance
 * ==: non-virtual inheritance
 *              BB
 *          /        \
 *      LB              RB
 *      |     \     /   |
 *      |       B       |
 *      LD      ||       RD
 *         \\   ||   //
 *              D
 */
struct BaseBase 
{
    BaseBase() { std::cout << "BaseBase" << std::endl; } 
    int iBB=1; 
};

struct LeftBase : public virtual BaseBase 
{
    LeftBase() { std::cout << "LeftBase" << std::endl; } 
    int iLB=2; 
};

struct RightBase : public virtual BaseBase 
{
    RightBase() { std::cout << "RightBase" << std::endl; }
    //int iRB=3; //--> uncomment here to resolve? problem
};

struct Base : public virtual LeftBase, public virtual RightBase 
{ 
    Base() { std::cout << "Base" << std::endl; }
    int iB=4; 
};

struct LeftDerived : public virtual LeftBase 
{
    LeftDerived() { std::cout << "LeftDerived  " << std::endl; }
    int iLD=5; 
};

template<typename DerivedType>
struct RightDerived : public virtual RightBase 
{
    RightDerived() { std::cout << "RightDerived  " << &( static_cast<DerivedType*>(this)->iLB ) /*<< " " << static_cast<DerivedType*>(this)->iLB*/ << std::endl; }
    int iRD=6; 
};

struct Derived : public Base, public LeftDerived, public RightDerived<Derived>   
{
    Derived() { std::cout << "Derived " << &(iLB) << std::endl; } 
    int iD=7; 
};


int main()
{
    Derived MyDerived;
}

I get the following output (printing from all constructors to show the order in which the bases are initialised):

BaseBase
LeftBase
RightBase
Base
LeftDerived
RightDerived  0xd5957b646068
Derived 0x7ffd19379408

while if I uncomment the int in 'RightBase' I get:

BaseBase
LeftBase
RightBase
Base
LeftDerived
RightDerived  0x7ffebf1fb948
Derived 0x7ffebf1fb948

More so than finding a solution (having the base non-empty is sort of one), I would like to learn why the above code is wrong, and in which situation I can possibly expect similar problems.

Tom_DB
  • 11
  • 1
  • 1
    You can't use `static_cast` to down-cast in the presence of virtual inheritance: [Why can't static\_cast be used to down-cast when virtual inheritance is involved?](https://stackoverflow.com/questions/7484913/why-cant-static-cast-be-used-to-down-cast-when-virtual-inheritance-is-involved) – Corristo Mar 03 '21 at 22:27
  • 2
    You apply `static_cast` with destination class that wasn't constructed yet and try to access one of it's members. This totally sounds like UB. Check if similar issues occur when you apply same routine in a member function - after the whole class instance was constructed. I believe it will work without issues. – ALX23z Mar 03 '21 at 22:37
  • @Corristo `static_cast` wouldn't compile if it was forbidden. It is just a lot more limited. I believe in his case it is ought to operate properly. He just mustn't use it in the middle of constructor. – ALX23z Mar 03 '21 at 22:39

0 Answers0