C++ c++;在类主体之外定义函数时派生构造函数-“;“无默认构造函数”;

C++ c++;在类主体之外定义函数时派生构造函数-“;“无默认构造函数”;,c++,constructor,C++,Constructor,我正在自学比亚恩·斯特劳斯特普的《编程原理》一书,在定义构造函数方面遇到了困难。这个问题需要使用从FLTK图形库构建的接口;一般来说,那里没有什么问题。我们必须从circle类中生成一个smileyface,它没有默认的构造函数-常规构造函数接受(x,y)点和半径。我希望能够进行一些计算/做其他事情-因此尝试在类主体之外为我的笑脸定义构造函数。这不起作用,我不断收到一个错误(来自visual studio)“Graph_lib::Circle类不存在默认构造函数” 基本上,上述方法不起作用。我认

我正在自学比亚恩·斯特劳斯特普的《编程原理》一书,在定义构造函数方面遇到了困难。这个问题需要使用从FLTK图形库构建的接口;一般来说,那里没有什么问题。我们必须从circle类中生成一个smileyface,它没有默认的构造函数-常规构造函数接受(x,y)点和半径。我希望能够进行一些计算/做其他事情-因此尝试在类主体之外为我的笑脸定义构造函数。这不起作用,我不断收到一个错误(来自visual studio)“Graph_lib::Circle类不存在默认构造函数”

基本上,上述方法不起作用。我认为出于某种原因,它试图以某种方式创建一个默认的圆,但是找不到它的默认函数(因为我还没有编写一个)然后抛出错误。我为这个函数尝试了大量不同的组合,但似乎无法让它不尝试并修正默认值。请注意,如果我在Smiley::Smiley中去掉l_eye和r_eye之前的“圆圈”类型,它仍然会抛出一个错误“调用没有适当运算符()的类类型的对象”或将函数转换为指向函数类型的指针”

但是,如果我只是在初始化列表中定义它,它就可以正常工作

struct Smiley :public Circle {
    Smiley(Point p, int rr) : Circle(p, rr), l_eye(Point(p.x - 50, p.y - 50), rr/8), r_eye(Point(p.x + 50, p.y - 50), rr/8) {}
    void draw_lines() const;
    void sc(Color c);

    Circle l_eye;
    Circle r_eye;
};
显然,这是一个非常简单的例子。但是,我认为这对我来说很重要,因为在未来的很多时候,我需要在外部构造函数中进行计算。如果有人能帮助解释问题所在,那就太好了。

该声明

Circle(p, rr);
创建一个不使用的临时
对象

然后

正在创建两个与同名成员变量完全无关的新对象和变量

出现的错误是因为编译器需要初始化(构造)基类和成员变量
l_-eye
r_-eye
,作为
Smiley
构造的一部分,并且此初始化是在调用
Smiley
构造函数体之前完成的


在某种程度上,您的构造函数:

Smiley::Smiley(Point p, int rr) {
    Circle(p, rr);
    Circle l_eye(Point(p.x - 50, p.y - 50), rr / 8);
    Circle r_eye(Point(p.x + 50, p.y - 50), rr / 8);    
}
相当于:

Smiley::Smiley(Point p, int rr)
    : Circle(), l_eye(), r_eye()  // Default initialization
{
    Circle(p, rr);
    Circle l_eye(Point(p.x - 50, p.y - 50), rr / 8);
    Circle r_eye(Point(p.x + 50, p.y - 50), rr / 8);    
}

如果
Circle
没有默认构造函数(它似乎没有,否则就不会出错),那么这是不可能的。

您可以在类外定义构造函数中编写初始值设定项列表,就像在类内定义构造函数中一样

如果我只是在初始化列表中定义它,它可以正常工作

struct Smiley :public Circle {
    Smiley(Point p, int rr) : Circle(p, rr), l_eye(Point(p.x - 50, p.y - 50), rr/8), r_eye(Point(p.x + 50, p.y - 50), rr/8) {}
    void draw_lines() const;
    void sc(Color c);

    Circle l_eye;
    Circle r_eye;
};
那么就这么做吧。这就是你应该做的。初始化列表就是为了这样做而存在的

将来会有很多次

在外部构造函数中执行计算

在紧急情况下,您可以编写一个助手函数并从中复制并初始化基类子对象:

Circle enormouslyComplicatedAuxiliaryFunction(Point p, int rr);

Smiley(Point p, int rr) : Circle(enormouslyComplicatedAuxiliaryFunction(p, rr)) { ... }

但是如果你发现自己做了很多事情,考虑重新设计<代码>循环>代码>。构造是简单的。如果你需要计算很多东西来创建你的基类对象,那么你可能应该有一个基类构造函数来计算那些东西。


(但是等等,如果
Circle
是抽象的呢?如果你需要很多东西来初始化一个抽象类子对象,那么它的设计几乎肯定会被破坏。)

请包含a和完整的错误消息OK,非常感谢您的帮助。1.首先构造基类,并使用初始化器列表2传递参数。调用派生类construcor,但首先使用初始化器列表。我的问题是1和2没有默认值。3.然后调用构造函数主体…My接下来的问题是:在实践中,我们真的需要构造函数体吗?因为实现构造函数体的唯一方法是使用默认类或初始化列表中的变量,然后必须在构造函数体中使用成员函数,然后再对数据进行第二次处理?@bigrig78对于简单的初始化,那么就可以了e全部在初始值设定项列表中,构造函数主体可以为空。好的,谢谢您的帮助:)辅助函数的要点很好。
Circle enormouslyComplicatedAuxiliaryFunction(Point p, int rr);

Smiley(Point p, int rr) : Circle(enormouslyComplicatedAuxiliaryFunction(p, rr)) { ... }