C++中,如果用户没有定义构造函数,则编译器会创建一个默认构造函数,且函数体是空的。它不会自动对数据成员进行初始赋值(在Java中,默认构造函数是会赋初始值的)。
同样地,如果用户没有定义拷贝构造函数,则编译器也会创建一个默认的拷贝构造函数。与默认构造函数不同,默认拷贝构造函数的函数体不为空,它会将传递进来的对象的所有数据成员拷贝给正在创建的对象。
场景1
用户只定义了拷贝构造,编译器是否还会创建默认构造函数?
如果用户创建了任意的构造函数,即使它是一个拷贝构造函数,编译器也不会再创建一个默认的构造函数了。
例如,下面的程序会编译失败。
#include <iostream>
using namespace std;
class Point
{
int x, y;
public:
//只定义了拷贝构造函数
Point(const Point &p) { x = p.x; y = p.y; }
};
int main()
{
Point p1; // 编译错误
Point p2 = p1;
return 0;
}
输出:
error: no matching function for call to 'Point::Point()
场景2
相反,如果用户只定义了构造函数,编译器是否会创建拷贝构造函数?
反过来的情况与上面的情况有所不同。即使用户没有定义拷贝构造,编译器会自动创建一个。即使用户定义了其它的构造函数(非拷贝构造),编译器也会创建一个拷贝构造。
例如,下面的程序可以编译通过。
#include <iostream>
using namespace std;
class Point
{
int x, y;
public:
Point(int i, int j) { x = 10; y = 20; }
int getX() { return x; }
int getY() { return y; }
};
int main()
{
Point p1(10, 20);
Point p2 = p1; // 编译正常。编译器会自动创建拷贝构造。
cout << "x = " << p2.getX() << " y = " << p2.getY();
return 0;
}
输出:
x = 10 y = 20
所以,仅当类中包含有指针成员,或动态分配的资源时,用户才需要自定义拷贝构造函数。否则就可以使用编译器生成的拷贝构造函数。
总结
参考C++ Object Model (by Lipman)
只有在下面的4种情况下,编译器会自动生成默认构造函数:
1. 类的成员对象有默认构造函数
2. 基类有默认构造函数
3. 包含有虚函数的类
4. 有Virtual Base Class(虚基类)的类