在其他 class 构造函数中使用 class 作为类型

Use class as type in other class constructor

我想在另一个 class 矩形中使用 class 点。

class Point
{
    int x, y;
    public:
    Point (int px, int py){
        x = px;
        y = py;
    }
};

class Rect
{
    Point top_left; 
    Point bottom_right;
    public:
    Rect (Point p1, Point p2){
        top_left = p1;
        bottom_right = p2;
    }
};

错误消息是:“main.cpp:31:30:错误:没有匹配函数来调用‘Rect::Point::Point()’” .在我的理解中,Rect class 的构造函数方法使用两个 Point 类型的参数来实例化一个 Rect 对象。我想我不能使用“Point”作为类型,因为它听起来像编译器想要调用一个函数。错误消息对我没有帮助,所以我希望你能。提前谢谢你。

在您给出的示例中,数据成员 top_leftbottom_right 在执行 Rect::Rect (Point, Point) 的主体之前 默认初始化 。这意味着在您的语句示例中:

Point top_left; //this statement needs default ctor in your example because this data member is default initialized 
Point bottom_right;//this statement needs default ctor in your example because this data member is default initialized 

需要默认构造函数 Point::Point()

但是 问题 是因为你的 class Point 有 user-defined 构造函数,编译器不会合成 默认构造函数 Point::Point().

有两种方法可以解决这个问题。

解决方案 1

首先,您可以为 class Point 添加默认构造函数,如下所示:

class Point
{
    int x, y;
    public:
        Point (int px, int py){
            x = px;
            y = py;
        }
        //default constructor
        Point(): x(0), y(0){
        }
};

Working demo.

在上面修改后的代码中,我添加了一个默认构造函数,它使用构造函数初始化列表来初始化数据成员xy

解决方案 2

我们还可以在构造函数Rect::Rect(Point, Point)中使用构造函数初始化列表来通过传递参数来初始化数据成员,而不是默认初始化它们。

class Rect
{
    Point top_left; 
    Point bottom_right;
    public:
    //use constructor initializer list to intialize the data members by passing arguments instead of default initializing them
    Rect (Point p1, Point p2): top_left(p1), bottom_right(p2){
       
    }
};

Working demo.

成员在构造函数主体运行之前被初始化。当你写:

Rect (Point p1, Point p2){
    top_left = p1;
    bottom_right = p2;
}

然后在执行构造函数之前初始化成员 top_leftbottom_right。因为 Point 没有默认构造函数,所以无法初始化成员。

要使用构造函数初始化成员,您应该使用成员初始化列表:

Rect (Point p1, Point p2) : top_left(p1), bottom_right(p2) { }

也可以通过为成员提供默认初始化程序来防止错误:

class Rect
{
    Point top_left{0,0}; 
    Point bottom_right{0,0};
    public:
    Rect (Point p1, Point p2){
        top_left = p1;
        bottom_right = p2;
    }
};

或者为 Point 提供默认构造函数。默认构造函数是可以在没有参数的情况下调用的构造函数。但是,在任何情况下,您都应该更喜欢成员初始化列表而不是构造函数主体中的赋值,因为初始化 + 赋值比仅初始化更昂贵。

问题是在创建Rect对象时,在执行Rect构造函数体之前构造并初始化了成员变量。

由于 Point 成员变量没有显式初始化,因此它们需要是默认可构造的,但它们不是,因为您没有默认的 Point 构造函数。

有几种可能的解决方案,其中最简单的一种是:

  1. 创建一个 Point 默认构造函数。它不需要做任何事情,可以由编译器生成(但你仍然必须告诉编译器生成它):

    class Point
    {
    public:
        Point() = default;
        ...
    };
    

    虽然现在可以默认构造 Point,但它会使 xy 成员未初始化。

但我更愿意推荐另一种解决方案:

  1. 创建一个Rect构造函数初始化列表来初始化Rect的成员变量:

    class Rect
    {
        Point top_left; 
        Point bottom_right;
    
    public:
        Rect(Point p1, Point p2)
            : top_left(p1), bottom_right(p2)
        {
            // Empty
        }
        ...
    };
    

第二个解决方案不需要 Point 默认构造函数。


至于为什么没有为Point创建默认构造函数,这是因为您声明了另一个构造函数。这禁止编译器生成自己的默认构造函数(没有像第一种选择那样被告知这样做)。