为什么调用基本构造函数而不是带参数的构造函数(虚拟继承)?

Why does the base constructor get called instead of the one with parameters (virtual inheritance)?

#include <iostream>

using namespace std;

class Point
{
    int x,y;
public:
    Point()
    {
        x=0;
        y=0;
    }
    Point(int x, int y)
    {
        this->x=x;
        this->y=y;
    }
    Point(Point &p)
    {
        x=p.x;
        y=p.x;
    }
    friend class Square;
};

class Square
{
    Point _point;
    int side;
public:
    Square() {cout<<"Square.\n";}
    Square(Point &p, int side_val): _point(p), side(side_val)
    {
        cout<<"Square constructor that should be used.\n";
    }
};

class Rectangle: public virtual Square
{
    int side2;
public:
    Rectangle() {}
    Rectangle(Point &p, int side_1, int side_2): Square(p,side_1), side2(side_2) {}
};

class Rhombus: public virtual Square
{
    Point opposite_point;
public:
    Rhombus() {cout<<"Rhombus. \n";}
    Rhombus(Point &p, Point &q, int side_1): Square(p, side_1), opposite_point(q)
    {
        cout<<"Rhombus constructor that should be used \n";
    }
};

class Paralellogram: public Rectangle, public Rhombus
{
public:
    Paralellogram(Point &p, Point &q, int side_1, int side_2): Rhombus(p,q,side_1),Rectangle(p,side_1,side_2)
    {
        cout<<"Parallelogram constructor that should be used\n";
    }
};

int main()
{
    Point down_left(3,5);
    Point up_right(2,6);
    int side_1=5;
    int side_2=7;
    Paralellogram par(down_left,up_right,side_1,side_2);
}

我得到的输出是:

Square
Rhombus constructor that should be used
Paralellogram constructor that should be used

我想要做的是实例化一个平行图,它结合了来自菱形和矩形的变量(它应该有一个_point、opposite_point、side、side2),我不想要他们加倍因此我使用虚拟继承。但是我打算使用的 Square 的构造函数永远不会被调用,即使是一次,而是调用基本构造函数。

我该怎么办?放弃虚拟继承?

在虚继承中,虚基是根据最派生的class构造的。

class Paralellogram: public Rectangle, public Rhombus
{
public:
    Paralellogram(Point &p, Point &q, int side_1, int side_2) :
        Square(), // You have implicitly that
        Rectangle(p,side_1,side_2),
        Rhombus(p,q,side_1)
    {
        cout<<"Parallelogram constructor that should be used\n";
    }
};

你可能想要

class Paralellogram: public Rectangle, public Rhombus
{
public:
    Paralellogram(Point &p, Point &q, int side_1, int side_2) :
        Square(p, side_1),
        Rectangle(p,side_1,side_2),
        Rhombus(p,q,side_1)
    {
        cout<<"Parallelogram constructor that should be used\n";
    }
};

Understanding virtual base classes and constructor calls 中所述:

There is always just one constructor call, and always of the actual, concrete class that you instantiate. It is your responsibility to endow each derived class with a constructor which calls the base classes' constructors if and as necessary, as you did in [Rectangle and Rhombus]'s constructor[s].

问问自己:如果 RectangleRhombus 调用不同意如何初始化 Square 的唯一(自虚拟)实例怎么办?我们应该听谁的?答案是两者都不是。当前 class,此处 Parallelogram,始终负责初始化虚拟基地。并且由于这里没有指定构造函数,所以认为Parallelogram调用了Square.

的默认构造函数