Compiler behavior when building a virtual base class

Consider this piece of code:

#include <iostream>

class A {
  public:
    A(int s) { std::cout << "A(" << s << ")\n"; }
};

class B1 : virtual public A {
  public:
    B1(int s1, int s2)
        : A{s1} { std::cout << "B1(" << s1 << "," << s2 << ")\n"; }
};

class B2 : virtual public A {
  public:
    B2(int s1, int s2)
        : A{s1} { std::cout << "B2(" << s1 << "," << s2 << ")\n"; }
};

class C1 : public B1, public B2 {
  public:
    C1() : B1{1,2}, B2{3,4}, A{5} {}
};

class C2 : public B1, public B2 {
  public:
    C2() : B1(1,2), B2(3,4), A{5} {}
};

int main()
{
    std::cout << "Create c1:\n";
    C1 c1;

    std::cout << "\n";
    std::cout << "Create c2:\n";
    C2 c2;

}

Class A is the virtual base class of B1 and B2. Classes C1 and C2 are identical, except that C1 uses {...}, and C2 uses (...)to build B1 and B2.

Due to the virtual inheritance used here, class A must be built as part of the construction of C1 or C2.

If I compile this code using Microsoft VS2015, it gives this output at startup:

Create c1:
A(5)
B1(1,2)
B2(3,4)

Create c2:
A(5)
B1(1,2)
B2(3,4)

as I expected.

But if I compile it using GCC (6.1.0), it will produce this output:

Create c1:
A(5)
A(1)
B1(1,2)
A(3)
B2(3,4)

Create c2:
A(5)
B1(1,2)
B2(3,4)

Here, the constructor is called three times when building c1, but only once when building c2.

Is this a bug in GCC, or am I misunderstood something?

+4
3

:

-, GCC . GCC 7.0.0 :

Create c1:
A(5)
B1(1,2)
B2(3,4)

Create c2:
A(5)
B1(1,2)
B2(3,4)
+1

, , ( ), ?!

0

:

    #include <iostream>

    class A {
       public:
          A(int s) { std::cout << "A(" << s << ")\n"; ms = s; };
          int ms;
          virtual void dummy() {std::cout << "Aaaaaa!" << std::endl;};
          virtual ~A() {std::cout << "~A(" << ms << ")\n";};
    };

    class B1 : virtual public A {
        public:
           B1(int s1, int s2)
              : A{s1} { std::cout << "B1(" << s1 << "," << s2 << ")\n"; };
    };

    class B2 : virtual public A {
        public:
           B2(int s1, int s2)
              : A{s1} { std::cout << "B2(" << s1 << "," << s2 << ")\n"; };
    };

       class C1 : public B1, public B2 {
           public:
              C1() : B1{1,2}, B2{3,4}, A{5}  {};
       };

       class C2 : public B1, public B2 {
           public:
              C2() : B1(1,2), B2(3,4), A{5} {};
       };

      int main()
      {
         {
             std::cout << "Create c1:\n";
             C1 c1;
             std::cout << "Calling A dummy on c1: " << std::endl;
             c1.dummy();
             std::cout << "Size of c1: " << sizeof(c1) << std::endl;
         }

         {
             std::cout << "\n";
             std::cout << "Create c2:\n";
             C2 c2;
             std::cout << "Calling A dummy on c2: " << std::endl;
             c2.dummy();
             std::cout << "Size of c2: " <<sizeof(c2) << std::endl;
         }

     }

GCC 5.4.0 :

  • c1:
  • (5)
  • (1)
  • 1 (1,2)
  • (3)
  • 2 (3,4)
  • c1:
  • !
  • c1: 32
  • ~ A (3)

  • Create c2:
  • A (5)
  • B1 (1,2)
  • B2 (3.4)
  • Dummy call on c2:
  • Ahhhhh!
  • Size c2: 32
  • ~ A (5)
0
source

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


All Articles