Why aren't virtual base constructors that are not standard, unless the main base explicitly calls them?

I would like to understand that WHY C ++ standardizes that virtual base constructors that are not standard cannot be called by the intermediate NOT of most derived classes, as in this code, when compiling with '-D_WITH_BUG_':

/*  A virtual base non-default constructor is NOT called UNLESS 
 *  the MOST DERIVED class explicitly invokes it
 */

#include <type_traits>
#include <string>
#include <iostream>

class A
{
public:
    int _a;
    A():  _a(1)
    {
        std::cerr << "A() - me: " << ((void*)this) << std::endl;
    }
    A(int a): _a(a)
    {
        std::cerr << "A(a) - me:" << ((void*)this) << std::endl;
    }
    virtual ~A()
    {
        std::cerr << "~A" << ((void*)this) << std::endl;
    }
};

class B: public virtual A
{
public:
    int _b;
    B(): A(), _b(2)
    {
        std::cerr << "B() - me: " << ((void*)this) << std::endl;
    }
    B(int b) : A(), _b(b)
    {
        std::cerr << "B(b) - me: " << ((void*)this) << std::endl;
    }
    B(int a, int b): A(a), _b(b)
    {
        std::cerr << "B(a,b) - me: " << ((void*)this) << std::endl;
    }
    virtual ~B()
    {
        std::cerr << "~B" << ((void*)this) << std::endl;
    }
};

class C: public virtual B
{
public:
    int _c;
    C(): B(), _c(3)
    {
        std::cerr  << "C()" << std::endl;
    }
    C(int a, int b, int c)
    :
#ifdef _WITH_BUG_    
    B(a,b)
#else
    A(a), B(b)
#endif    
    , _c(c)
    {
        std::cerr  << "C(a,b) - me: " << ((void*)this) << std::endl;    
    }
    virtual ~C()
    {
        std::cerr << "~C" << ((void*)this) << std::endl;
    }  
};
extern "C"
int main(int argc, const char *const* argv, const char *const* envp)
{
    C c(4,5,6);
    std::cerr << " a: " << c._a  << " b: " << c._b << " c: " << c._c 
              <<  std::endl;
    return 0;
}

So, when compiling WITHOUT -D_WITH_BUG_, the code prints:

$ g++ -I. -std=gnu++17 -mtune=native -g3 -fPIC -pipe -Wall -Wextra \
  -Wno-unused -fno-pretty-templates -Wno-register  \
  tCXX_VB.C -o tCXX_VB 
$ ./tCXX_VB
A(a) - me:0x7ffc410b8c10
B(b) - me: 0x7ffc410b8c00
C(a,b) - me: 0x7ffc410b8bf0
a: 4 b: 5 c: 6
~C0x7ffc410b8bf0
~B0x7ffc410b8c00
~A0x7ffc410b8c10

But when compiled with -D_WITH_BUG_:

$ g++ -I. -std=gnu++17 -mtune=native -g3 -fPIC -pipe -Wall -Wextra \ 
  -Wno-unused -fno-pretty-templates -Wno-register \
  -D_WITH_BUG_ tCXX_VB.C -o tCXX_VB
$ ./tCXX_VB
A() - me: 0x7ffd7153cb60
B(a,b) - me: 0x7ffd7153cb50
C(a,b) - me: 0x7ffd7153cb40
a: 1 b: 5 c: 6
~C0x7ffd7153cb40
~B0x7ffd7153cb50
~A0x7ffd7153cb60

Why is B (int a, int b) calling A (a) ignored here? I understand that the C ++ standard requires, but why? What is rational?

B:  B b (4,5); b._a 4; B C:  C c (4,5,6) C:: a 1, IFF c A (a). , B (a, b) , . . , ++ ?

+4
3

- . , :

  A
 / \
B   C
 \ /
  D

, A. B , C, - , . , ? - , ! , B D, A, B .

:

A
|
B
|
C

C - A B. B A , .

+3

- virtual base class. A - , .
, , .
, .
class A { ...}
class B: virtual public A {...}
class C: virtual public A {...}
class D: public B, public C {...}
, . . , D, B:: A C:: A . B, C. , , . .

+1

- . .

B (int a, int b) A (a) ?

Because a unique Sub object has already been created. The constructor is not an ordinary function; you cannot just name it anywhere.

You can write

C(int a, int b, int c)
    : A(a), B(a, b), _c(c)
    { ... }

which will give the body the B::B(int, int)parameter that was passed toA::A(int)

+1
source

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


All Articles