如果类没有构造函数,编译器会为它创建一个默认构造函数吗?
新加入C++的程序员通常有两个共同的误解: 为每个未定义类合成默认构造函数。
来自C++对象模型内部的书
我不知所措..。
发布于 2012-03-09 15:57:31
这一点在摘取这一引文的一节中得到了很好的解释。我将不完整地解释它,但这里是一节内容的简短摘要。
首先,您需要理解以下术语:implicitly-declared、implicitly-defined、trivial、non-trivial和synthesized (斯坦利普曼使用的术语,但在标准中没有使用)。
implicitly-declared
如果类中没有implicitly-declared构造函数,则构造函数是类的user-declared。例如,该类struct T { };不声明任何构造函数,因此编译器隐式声明默认构造函数。另一方面,这个类struct T { T(int); };声明了一个构造函数,所以编译器不会声明一个隐式默认构造函数。除非您定义了自己的默认构造函数,否则您将无法在没有参数的情况下创建T实例。
implicitly-defined
implicitly-declared构造函数在使用时是implicitly-defined,即在没有参数的情况下创建实例时。假设下面的类是struct T { };,行T t;将触发T::T()的定义。否则,您将有一个链接器错误,因为构造函数将被声明,但没有定义。但是,隐式定义的构造函数不一定有任何与其相关联的代码!默认构造函数是合成的(意味着某些代码是在特定情况下为它创建的)。
平凡构造函数
在以下情况下,implicitly-declared默认构造函数为trivial:
trivial构造函数和trivial构造函数。在这种情况下,默认编译器没有什么可做的,因此没有为其合成代码。例如,在以下代码中
struct Trivial
{
int i;
char * pc;
};
int main()
{
Trivial t;
}t的构造不涉及任何操作(通过查看生成的程序集:没有调用构造函数来构造t)。
非平凡
另一方面,如果类不满足上述三项要求,那么它的implicitly-declared默认构造函数将是non-trivial,这意味着它将涉及一些必须执行的操作,以便尊重语言语义。在这种情况下,编译器将synthesize执行这些操作的构造函数的实现。
例如,考虑以下类:
struct NonTrivial
{
virtual void foo();
};由于它有一个虚拟成员函数,它的默认构造函数必须将虚拟表指针设置为正确的值(当然,假设实现使用虚拟方法表)。
类似地,该类的构造函数
struct NonTrivial
{
std::string s;
};必须调用字符串默认构造函数,因为它不是trivial。要执行这些操作,编译器将为默认构造函数生成代码,并在创建没有参数的实例时调用它。您可以通过查看与这个实例化NonTrivial n;对应的程序集来检查这一点(除非构造函数已经内联,否则您应该会看到一个函数调用)。
摘要
当您不为类提供任何构造函数时,编译器将隐式声明默认构造函数。如果您尝试使用它,编译器将隐式地定义它,如果可以的话(它并不总是可能的,例如,当一个类有一个非默认的可构造成员时)。但是,这个隐式定义并不意味着生成任何代码。编译器只需要为构造函数(合成)生成代码,这意味着它涉及实现语言语义所需的某些操作。
N.B.
斯坦利普曼的“内部C++对象模型”和这个答案涉及(一种可能的)实现的C++,而不是它的语义。因此,上述任何一个都不能推广到所有编译器:据我所知,即使是为一个普通的构造函数,实现也完全允许生成代码。从C++用户的角度来看,重要的是“隐式声明/定义”方面(以及琐碎/非平凡的区分,因为它有一些含义(例如,具有非平凡构造函数的类的对象不能是联合的成员)。
发布于 2012-03-09 14:39:39
我认为误解是:
为每个未定义类合成默认构造函数。
人们认为不接受参数的默认构造函数将始终生成,如果您不自己声明它。
但是,这是不正确的,因为如果您自己声明任何构造函数,则不会自动创建默认构造函数。
class MyClass {
public:
MyClass(int x) {}; // No default constructor will be generated now
};这将导致一些问题,比如初学者期望使用这样的MyClass:
MyClass mc;这将无法工作,因为没有接受任何args的默认构造函数。
编辑作为OP仍然有点困惑。
假设我上面的MyClass是这样的:
class MyClass {
};
int main() {
MyClass m;
}这将编译,因为编译器将自动生成默认构造函数MyClass(),因为使用了MyClass。
现在看一看这个:
#include <iostream>
class MyClass {
};
int main() {
std::cout << "exiting\n";
}如果这是唯一的代码,编译器甚至不会去生成默认的构造函数,因为从来没有使用过MyClass。
现在这是:
#include <iostream>
class MyClass {
public:
MyClass(int x = 5) { _x = x; }
int _x;
};
int main() {
MyClass m;
std::cout << m._x;
}编译器不会生成默认的构造函数MyClass(),因为类已经有了由我定义的构造函数。这将有效,MyClass(int x = 5)作为默认构造函数工作,因为它可以不接受任何参数,但它不是由编译器生成的。
最后,初学者可能会遇到问题:
class MyClass() {
public:
MyClass(int x) { _x = x; }
int _x;
};
int main() {
MyClass m;
}上面的代码将在编译期间抛出一个错误,因为MyClass m需要一个默认的构造函数(没有参数)才能工作,但是您已经声明了一个接受int的构造函数。在这种情况下,编译器也不会生成无参数构造函数。
发布于 2012-03-09 14:36:09
如果以下情况下,将为未定义一个类的每个类合成默认构造函数:
https://stackoverflow.com/questions/9635772
复制相似问题