这是代码:
class cat
{
private:
int height;
public:
cat (int inputHeight);
};
cat::cat (int inputHeight)
{
height = inputHeight;
}
class twoCats
{
private:
cat firstCat;
cat secondCat;
public:
twoCats (cat theFirstCat);
void addSecondCat (cat theSecondCat);
};
twoCats::twoCats (cat theFirstCat)
{
firstCat = theFirstCat;
}
void twoCats::addSecondCat (cat theSecondCat)
{
secondCat = theSecondCat;
}
int main() {return 0;}
这些是错误:
main.cpp: In constructor ‘twoCats::twoCats(cat)’:
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’
main.cpp:24:34: note: candidates are:
main.cpp:9:1: note: cat::cat(int)
main.cpp:9:1: note: candidate expects 1 argument, 0 provided
main.cpp:1:7: note: cat::cat(const cat&)
main.cpp:1:7: note: candidate expects 1 argument, 0 provided
main.cpp:24:34: error: no matching function for call to ‘cat::cat()’
main.cpp:24:34: note: candidates are:
main.cpp:9:1: note: cat::cat(int)
main.cpp:9:1: note: candidate expects 1 argument, 0 provided
main.cpp:1:7: note: cat::cat(const cat&)
main.cpp:1:7: note: candidate expects 1 argument, 0 provided
我不明白以下内容:
twoCats
的构造函数会尝试调用cat
的默认构造函数?当然,它不需要构造cat
的实例,因为初始化twoCats
时它将传递已经初始化的cat
实例,该实例将传递int height
参数?g++ main.cpp
。答案 0 :(得分:5)
您需要一个默认构造函数或明确初始化twoCats
构造函数初始化列表中的cat对象,以避免默认构造。
为什么twoCats的构造函数会尝试调用默认值 猫的构造函数?当然它不需要构造一个实例 当catC初始化时,它将被传递 初始化的cat实例,它将传递给int高度 参数
需要为cat
个对象构建默认值
private:
cat firstCat;
cat secondCat;
在课程twoCats
中因为您没有初始化它们。在你的构造函数
中cat::cat (int inputHeight)
{
height = inputHeight;
^^^^^^^^^^^^^^^^^^^^
} // this is assignment
这是对已创建对象的赋值。
规则如下:如果你没有在ctor
初始化列表中显式初始化实例,那么
ctor
被称为ctor
body。因此,如果未在初始化列表中初始化,则会面临额外调用的惩罚。
C ++标准版n3337 § 12.6.2 / 10初始化基础和成员
在非委托构造函数中,初始化继续进行 以下顺序:
- 首先,仅适用于派生程度最高的类(1.8)的构造函数, 虚拟基类按照它们出现在的顺序进行初始化 深度优先从左到右遍历有向无环图 基类,其中“从左到右”是出现的顺序 派生类base-specifier-list中的基类。
- 然后,直接基类按声明顺序初始化为 它们出现在base-specifier-list中(无论顺序如何 MEM-初始化)。
- 然后,按照它们的顺序初始化非静态数据成员 在类定义中声明(再次无论顺序如何 MEM-初始化)。
- 最后,执行构造函数体的复合语句。
[注:声明命令的目的是确保基础和 成员子对象以相反的顺序销毁 初始化。 - 结束说明]
答案 1 :(得分:2)
我会像这样初始化类twoCats
:
class twoCats
{
private:
cat firstCat;
cat secondCat;
public:
twoCats (const cat& theFirstCat, const cat& theSecondCat)
: firstCat (theFirstCat), secondCat (theSecondCat)
{
}
};
这里重要的部分是构造函数:
之后的冒号。它启动成员初始化列表,如果可能的话,应该初始化所有类数据成员。
数据成员的初始化在C ++中是一个非常复杂的问题,我建议你谷歌吧。
特别是,由于您有两个类类型的成员,编译器无论如何都会尝试在构造函数中初始化它们。它对每只猫都这样做,这可能是你得到错误消息块两次的原因。在默认情况下,编译器尝试使用默认构造函数(即没有参数的构造函数)初始化cat数据成员。不幸的是,cat
没有默认的构造函数,因为你用一个参数声明了一个。换句话说,每个cat必须用一个参数初始化(或复制,或在C ++ 11中移动)。
我不建议在没有参数的情况下向cat
声明一个额外的构造函数:似乎没有猫的“默认高度”,而另一个答案建议的-1
非常奇怪:它似乎没有构造一个有效的对象,你必须在使用任何cat
的成员函数之前检查这个默认值。
编辑:这是从格式的角度来看。至于程序的语义,复制猫可能是错误的。也许你确实需要一个引用(或指针)你初始化你的两个猫的对象,可能不是。
答案 2 :(得分:1)
两个cat实例必须在它们开始存在时初始化。
为避免这种情况,您可以在需要时将每个实例创建推迟。
一种简单而安全的方法是使用std::vector
来保存实例。
class cat
{
private:
int height;
public:
cat (int inputHeight);
};
cat::cat (int inputHeight)
{
height = inputHeight;
}
#include <vector>
#include <utility>
class twoCats
{
private:
std::vector<cat> cats_;
public:
twoCats (cat theFirstCat)
{ cats_.push_back( std::move( theFirstCat ) ); }
void addSecondCat (cat theSecondCat)
{ cats_.push_back( std::move( theSecondCat ) ); }
};
int main() {return 0;}
或者,您可以使用boost::optional
。
或动态分配实例(使用unique_ptr
之类的智能指针来管理生命周期。)
或者,让猫可以默认构建。
如a comment中的“thang”所述,原始设计并不能保证twoCats
有两只猫。它可以只有一只猫,或三只或更多只猫。因此,更改设计是个好主意。
例如,有一个带有两个cat参数或cat高度的构造函数。
或者换个例子,更改twoCats
的名称。
答案 3 :(得分:0)
作为你的班级名字(twoCats),它代表两只猫总是。这些小猫可以活着,死亡甚至还没有出生。但它应该是两个。
你的设计在某种意义上是错误的:
cat
应该能够代表非出生的猫(所以它应该有
公共默认构造函数最初将对象设置为非生成状态)或