写了又删,删了又写,才发现这一章节不好描述。
那就假定个前提吧,假定已经知道:
① C++的类有构造函数。 ② 如果不提供任何构造函数,那编译器会生成默认的无参构造函数--默认构造函数只会进行成员变量的初始化。 ③ 如果提供了任何一个构造函数,那编译器就不会再生成默认的无参构造函数。 ④ 函数的形参都是实参的副本(引用类型除外)。 ⑤ 构造函数也是函数。
⑥ 直接初始化是在括号()中,复制初始化则使用=赋值操作符---注意,是定义,不是赋值。
⑦ 针对⑥,Person p2=p1;这是复制初始化! p2=p3;这才是赋值!!!
在此基础上,稍作推理:
一、如果构造函数是单形参、且形参类型为该类的类型的构造函数:
以 class Person 为例,
string name="anonymous"; int age=18; Person p1(name, age); Person p2(p1); //note this
根据上面前提的④,p2 需要 p1 的一个副本(复制一个),这时就出现问题了:该怎么复制?
这就是复制构造函数的作用了--用于指明如何复制。
再推理一下,如果不能使用副本,那还能使用什么?必须是引用啊(不要说指针,囧)!所以复制构造函数就是单形参、且形参类型为该类类型的引用 (常const修饰)的构造函数。
class Person{ public: Person(const Person&); //copy-constructor .... };
需要说明的是,编译器会自动生成一个默认的复制构造函数,原则就是一一复制成员变量。这里面又存在一个问题,如果存在指针类型的成员变量,那么与其他成员变量不同的是,复制后的指针仍然指向同一个地址!这可能会导致很严重的bug。如下:
#include <iostream> #include <string> using namespace std; //注意,有指针成员,但没有自定义复制构造函数。 //这时,其他成员复制时都是副本,而指针成员却指向同一个地址。 class HasPtr{ private: int *ptr; int val; public: HasPtr(int *p, int i):ptr(p), val(i){} int *get_ptr() const { return ptr; } void set_ptr(int *p){ ptr=p; } int get_int() const { return val; } void set_int(int i){ val=i; } int get_ptr_val() const { return *ptr; } void set_ptr_val(int i) const { *ptr = i; } //why not take a ref? }; int main(){ int obj=10; HasPtr ptr1(&obj, 42); HasPtr ptr2(ptr1); // copy-constructor cout<<ptr1.get_ptr()<<"--"<<ptr1.get_ptr_val()<<endl; cout<<ptr2.get_ptr()<<"--"<<ptr2.get_ptr_val()<<endl; ptr1.set_int(3); ptr2.set_int(5); cout<<ptr1.get_int()<<"--"<<ptr2.get_int()<<endl; ptr1.set_ptr_val(7); cout<<ptr1.get_ptr()<<"--"<<ptr1.get_ptr_val()<<endl; cout<<ptr2.get_ptr()<<"--"<<ptr2.get_ptr_val()<<endl; cout<<"-----------"<<endl; int *ip=new int(42); HasPtr ptr(ip, 2); delete ip; ptr.set_ptr_val(3);//OOPS! error return 0; }