本文共 3147 字,大约阅读时间需要 10 分钟。
目录
拷贝构造函数是类的一个成员函数,用于使用另一个对象来初始化本对象。拷贝构造函数遵循下面的函数基本原型:
ClassName (const ClassName &old_obj); 下面例子是一个简单的拷贝构造函数:#includeclass Point{private: int x, y;public: Point(int x1, int y1) { x = x1; y = y1; } // 拷贝构造函数 Point(const Point &p2) {x = p2.x; y = p2.y; } int getX() { return x; } int getY() { return y; }};int main(){ Point p1(11, 22); // 调用普通构造函数 Point p2 = p1; // 调用拷贝构造函数 std::cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY() << std::endl; std::cout << "p2.x = " << p2.getX() << ", p2.y = " << p2.getY() << std::endl; return 0;}
输出:
p1.x = 11, p1.y = 22 p2.x = 11, p2.y = 221. 按值返回类的对象
2. 做为参数按值传递 3. 相同类中的一个对象基于另一个对象来构造. 4. 编译器产生临时对象但是,不保证拷贝构造函数在上面所有case中都能被调用到。因为C++标准允许编译器在某些情况下优化对象拷贝方式。
其中一个例子就是返回值的优化(return value optimization)(也称为RVO, 具体可参考http://en.wikipedia.org/wiki/Return_value_optimization)。如果没有自定义的拷贝构造函数,则编译器会自动创建一个默认的拷贝构造函数,来实现成员的自动拷贝。
通常情况下这个默认的拷贝构造函数可以正常运行。但是,如果一个对象拥有指针,或者有任何运行时分配的资源,例如文件句柄,网络连接等,则需要自定义的拷贝构造函数。否则会出现一些意想不到的结果。下面两个表达式哪个调用拷贝构造,哪个调用赋值运算符?
MyClass t1, t2; MyClass t3 = t1; // case1 t2 = t1; // case2当使用一个已有对象,创建新的对象时,就调用拷贝构造,如case1所示。
当一个已有对象被赋予新值(来自另一个对象)时,则调用赋值运算符,如case2所示。下面的类需要定义拷贝构造函数。
#include#include class String{private: char *s; int size;public: String(const char *str = NULL); // 构造函数 ~String() { delete [] s; } // 析构函数 String(const String&); // 拷贝构造函数 void print() { std::cout << s << std::endl; } void change(const char *);};String::String(const char *str){ size = strlen(str); s = new char[size+1]; strcpy(s, str);}void String::change(const char *str){ delete [] s; size = strlen(str); s = new char[size+1]; strcpy(s, str);}String::String(const String& old_str){ size = old_str.size; s = new char[size+1]; strcpy(s, old_str.s);}int main(){ String str1("suv"); String str2 = str1; str1.print(); str2.print(); str2.change("bus"); str1.print(); str2.print(); return 0;}
输出:
suv suv suv bus如果上述代码中,删除了拷贝构造函数,会出现怎样的情况?
#include#include using namespace std;class String{private: char *s; int size;public: String(const char *str = NULL); // constructor ~String() { delete [] s; } // destructor void print() { cout << s << endl; } void change(const char *);};String::String(const char *str){ size = strlen(str); s = new char[size+1]; strcpy(s, str);}void String::change(const char *str){ delete [] s; size = strlen(str); s = new char[size+1]; strcpy(s, str);}int main(){ String str1("suv"); String str2 = str1; str1.print(); str2.print(); str2.change("bus"); str1.print(); str2.print(); return 0;}
输出:
suv suv bus bus可以看到,结果不是所期望的。对str2的操作,影响到了str1。这就是上面说的,涉及到资源共享时,需要定义独立的拷贝构造函数。
答案是可以!将类的拷贝构造函数定义为private, 则类的对象是不可拷贝的。这对于有指针成员或者会动态分配资源的类特别有用。
在这种情况下,我们可以自定义拷贝构造函数,像上面string例子那样,或者将拷贝构造定义为private,这样用户可以发现编译错误。拷贝构造函数中的参数,必须使用引用传递。
为什么呢?如果对象按值传递的话,会调用拷贝构造函数。这样拷贝构造函数中再次调用拷贝构造函数,会形成一个无限循环。所以,编译器禁止按值传递参数。
可以参考本系列的后续篇章。
转载地址:http://iqeji.baihongyu.com/