1、复制构造函数
如果代码中没有为某个类定义复制构造函数,那么编译器就会隐式声明一个拷贝构造函数。比如下面的constructor.cpp中的Point类,我并没有创建Point(Point& p)形式的构造函数,但是Point b(a)却可以成功。
#include
#include
using std::string;
class Point{
public:
Point(int x_value,int& y_value, const string& description_value):x(x_value),y(y_value),description(description_value){
}//初始化列表
string getDescription(){
return description;
}
void setDescription(const string& description_value){
description=description_value;
}
int getX(){
return x;
}
void setX(int x_value){
x=x_value;
// printf("x=%d,x_value=%d\n",x,x_value);
}
int getY(){
return y;
}
void setY(int& y_value){
y=y_value;
}
private:
int x,&y;
string description;
};
int main(){
int y1=2;
string s1="this is a";
Point a(1,y1,s1);
Point b(a);//调用拷贝构造函数
printf("a.x=%d,a.y=%d,a.description=%s\n",a.getX(),a.getY(),a.getDescription().c_str());
printf("b.x=%d,b.y=%d,b.description=%s\n",b.getX(),b.getY(),b.getDescription().c_str());
a.setX(3);
int y2=3;
string s2="this is a changed";
a.setY(y2);
a.setDescription(s2);
printf("after alter,a.x=%d,a.y=%d,a.description=%s\n",a.getX(),a.getY(),a.getDescription().c_str());
printf("after alter,b.x=%d,b.y=%d,b.description=%s\n",b.getX(),b.getY(),b.getDescription().c_str());
}
g++ constructor.cpp
./a.out
log打印如下:
a.x=1,a.y=2,a.description=this is a
b.x=1,b.y=2,b.description=this is a
after alter,a.x=3,a.y=3,a.description=this is a changed
after alter,b.x=1,b.y=3,b.description=this is a
值得注意的是当类的成员是const类型、引用类型、未提供默认构造函数的类类型时必须使用构造函数初始化列表,如果使用函数赋值的话会报error: uninitialized reference member。并且,初始化列表比先初始化再赋值的方式更加有效率。
2、移动构造函数
为了避免不必要的资源创建与释放,C++ 11中新增了移动资源而非拷贝创建资源的功能,对于将要消亡的源对象,将源对象所占资源通过右值引用的方式移动到目标对象中,从而避免销毁源对象资源以及为新对象开辟新空间放置资源,尤其对于占用内存大的对象
#include
#include
using std::string;
class Point{
public:
Point(int& x_value,int y_value, const string& description_value):x(&x_value),y(y_value),description(description_value){
printf("calling constructor...\n");
}
Point(Point &&p):x(p.x),y(p.y),description(p.description){
p.x=nullptr;
printf("calling move constructor...\n");
}
Point():x(new int(0)),y(0),description(""){
printf("calling default constructor...\n");
}
Point(Point& p):x(p.x),y(p.y),description(p.description){
printf("calling copy constructor...\n");
}
~Point(){
printf("calling destructor...\n");
}
int getY(){
return y;
}
private:
int y;
int* x;
string description;
};
Point getPoint(){
return Point();
}
int main(){
printf("getY()=%d\n",getPoint().getY());
// Point b(a);
return 0;
}
g++ constructor.cpp -std=c++11 -fno-elide-constructors
./a.out
log打印如下:
calling default constructor...
calling move constructor...
calling destructor...
getY()=0
calling destructor...
3、委托构造函数
委托构造函数调用其他构造函数来完成构造细节,比如下面13行的无参构造函数去调用第6行的三个参数的构造函数从而完成成员变量的初始化。
#include
#include
using std::string;
class Point{
public:
Point(int* x_value,int y_value, string description_value):x(x_value),y(y_value),description(description_value){
printf("calling constructor...\n");
}
Point(Point &&p):x(p.x),y(p.y),description(p.description){
p.x=nullptr;
printf("calling move constructor...\n");
}
Point():Point(new int(0),0,"aaa"){
printf("calling default constructor...\n");
}
~Point(){
printf("calling destructor...\n");
}
int getY(){
return y;
}
private:
int y;
int* x;
string description;
};
Point getPoint(){
return Point();
}
int main(){
printf("getY()=%d\n",getPoint().getY());
// Point b(a);
return 0;
}
编译执行后log打印如下,可以看到先打印了三个参数的构造函数,再去打印无参构造函数
calling constructor...
calling default constructor...
calling move constructor...
calling destructor...
getY()=0
calling destructor...