1、复制构造函数
如果代码中没有为某个类定义复制构造函数,那么编译器就会隐式声明一个拷贝构造函数。比如下面的constructor.cpp中的Point类,我并没有创建Point(Point& p)形式的构造函数,但是Point b(a)却可以成功。
#include <stdio.h> #include <string> 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 <stdio.h> #include <string> 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 <stdio.h> #include <string> 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...