复制构造函数 与 赋值函数 的区别
来源:互联网 发布:淘宝一元拍手机在哪 编辑:程序博客网 时间:2024/06/05 09:32
转自:http://www.cnblogs.com/kaituorensheng/p/3245522.html
构造函数、析构函数、赋值函数是每个类最基本的的函数。每个类只有一个析构函数和一个赋值函数。但是有很多构造函数(一个为复制构造函数,其他为普通构造函数。对于一个类A,如果不编写上述四个函数,c++编译器将自动为A产生四个默认的函数,即:
- A(void) //默认无参数构造函数
- A(const A &a) //默认复制构造函数
- ~A(void); //默认的析构函数
- A & operator = (const A &a); //默认的赋值函数
既然能自动生成函数,为什么还需要自定义?原因之一是“默认的复制构造函数”和"默认的赋值函数“均采用”位拷贝“而非”值拷贝“
位拷贝 v.s. 值拷贝
为便于说明,以自定义String类为例,先定义类,而不去实现。
#include <iostream>using namespace std;class String { public: String(void); String(const String &other); ~String(void); String & operator =(const String &other); private:
char *m_data;
int val;};
位拷贝拷贝的是地址,而值拷贝拷贝的是内容。
如果定义两个String对象a, b。当利用位拷贝时,a=b,其中的a.val=b.val;但是a.m_data=b.m_data就错了:a.m_data和b.m_data指向同一个区域。这样出现问题:
- a.m_data原来的内存区域未释放,造成内存泄露
- a.m_data和b.m_data指向同一块区域,任何一方改变,会影响到另一方
- 当对象释放时,b.m_data会释放掉两次
因此
当类中还有指针变量时,复制构造函数和赋值函数就隐含了错误。此时需要自己定义。
结论
- 有一种特别常见的情况需要自己定义复制控制函数:类具有指针哈函数。
- 赋值操作符和复制构造函数可以看成一个单元,当需要其中一个时,我们几乎也肯定需要另一个
- 三法则:如果类需要析构函数,则它也需要赋值操作符和复制构造函数
注意
- 如果没定义复制构造函数(别的不管),编译器会自动生成默认复制构造函数
- 如果定义了其他构造函数(包括复制构造函数),编译器绝不会生成默认构造函数
- 即使自己写了析构函数,编译器也会自动生成默认析构函数
因此此时如果写String s是错误的,因为定义了其他构造函数,就不会自动生成无参默认构造函数。
复制构造函数 v.s. 赋值函数
#include <iostream>#include <cstring>using namespace std;class String { public: String(const char *str); String(const String &other); String & operator=(const String &other); ~String(void); private: char *m_data;};String::String(const char *str){ cout << "自定义构造函数" << endl; if (str == NULL) { m_data = new char[1]; *m_data = '\0'; } else { int length = strlen(str); m_data = new char[length + 1]; strcpy(m_data, str); }}String::String(const String &other){ cout << "自定义拷贝构造函数" << endl; int length = strlen(other.m_data); m_data = new char[length + 1]; strcpy(m_data, other.m_data);}String & String::operator=(const String &other){ cout << "自定义赋值函数" << endl; if (this == &other) { return *this; } else { delete [] m_data; int length = strlen(other.m_data); m_data = new char[length + 1]; strcpy(m_data, other.m_data); return *this; }}String::~String(void){ cout << "自定义析构函数" << endl; delete [] m_data;}int main(){ cout << "a(\"abc\")" << endl; String a("abc"); cout << "b(\"cde\")" << endl; String b("cde"); cout << " d = a" << endl; String d = a; cout << "c(b)" << endl; String c(b); cout << "c = a" << endl; c = a; cout << endl;}
执行结果
0 0
- 复制构造函数与赋值函数的区别
- 复制构造函数 与 赋值函数 的区别
- 复制构造函数 与 赋值函数 的区别
- 复制构造函数 与 赋值函数 的区别
- 复制构造函数 与 赋值函数 的区别
- 复制构造函数与赋值操作符之间的区别
- 复制构造函数与赋值操作符之间的区别
- 复制构造函数与赋值操作符之间的区别
- 复制构造函数(拷贝构造函数)与赋值函数的区别
- 复制构造函数跟赋值构造函数的区别
- 复制构造函数跟赋值构造函数的区别
- 复制构造函数跟赋值构造函数的区别
- 复制构造函数与赋值构造函数
- 复制构造函数与赋值构造函数
- 复制构造函数和赋值函数的区别
- 复制构造函数 与 赋值函数 的区别以及应该注意的问题
- 复制构造函数 与 赋值操作函数
- 重载赋值函数与复制构造函数
- 肿瘤诊断(三维BFS)
- 17.2.17 关键字 注释 标识符 变量
- Unit4二进制存储、运算符、引用数据类型初步认识
- 输入中缀或后缀表达式,输出值
- 【Linux】CentOS 7通过Firewall开放防火墙端口
- 复制构造函数 与 赋值函数 的区别
- 12个最应该使用的Linux服务器OS(下)
- 1078. Hashing
- Java String 相关的面试题
- 1079. Total Sales of Supply Chain
- 《MySQL必知必会》学习笔记十五(触发器)------掌握部分
- 关于C++中"!"的非主流写法
- python常见需注意操作——稀疏矩阵内元素的放缩
- hdu5974