【C++】拷贝构造函数和赋值函数
2015-08-05 15:36
525 查看
<span style="font-family:Microsoft YaHei;">#include <iostream> using namespace std; class String { public: String() ; String(const String &other) ; ~String() ; String & operator = (const String &other) ; private: char *m_data; int val; };</span>
位拷贝和值拷贝
构造函数、析构函数、赋值函数是每个类最基本的函数。每个类只有一个析构函数和一个赋值函数。但有很两个构造函数,一个为拷贝构造函数,其他为普通构造函数。对于一个类,如果不编写这四个函数,C++编译器将自动为A产生四个默认函数。那么既然能自动生成函数,为什么还要自定义?原因之一是默认的拷贝构造函数和默认的赋值函数都采用的是位拷贝而非值拷贝。
位拷贝拷贝的是地址,值拷贝拷贝的是内容。
在上面定义的String类里,如果定义两个String的对象a和b。当利用位拷贝时,a = b,其中a.val = b.val; 这个没问题
但是a.m_data = b.m_data就错了,a.m_data 和b.m_data作为指针将指向同一个区域。这样出现问题:
1. a.m_data 原来的内存区域未释放,造成内存泄露
2.
a.m_data和b.m_data指向同一块区域,任何一方改变将会影响到另一方
3. 当对象释放时,b.m_data会释放两次
因此
当类中含有指针变量时,默认拷贝构造函数和默认赋值函数由于使用位拷贝就隐含了错误,这时需要自己定义。
结论
1. 有一中特别常见的情况需要自己定义拷贝构造函数:类具有指针函数
2. 赋值操作符和拷贝构造函数可以看成一个单元,当需要其中一个时,我们几乎也肯定需要另一个
3. 三法则:如果类需要析构函数,则它也需要赋值操作符和拷贝构造函数
注意
1. 如果没有定义拷贝构造函数,编译器会自动生成默认的拷贝构造函数
2. 如果定义了其他构造函数,包括拷贝构造函数,编译器绝不会生成默认构造函数
3. 即使自己写了析构函数,编译器也会自动生成默认析构函数
拷贝构造函数 VS 赋值函数
/* * copy.cpp * * Created on: 2015?8?5? * Author: nanzhou */ #include <iostream> using namespace std; class String { public: String(const char *str) ; String(const String &other) ; ~String() ; String & operator = (const String &other) ; private: char *m_data; }; String::String(const char *str) { cout << "zidingyi Constructor" << endl; if (NULL == str) { 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 << "zidingyi Copy Constructor" << 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 << "zidingyi fuzhi function" << endl; if ( this == &other) { return *this; } else { delete [] m_data; int length = strlen(other.m_data); m_data = new char[lenght + 1]; strcpy (m_data, other.m_data); return *this; } } String::~String() { cout << "zidingyi xigou function" << 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 = a" << endl; String c(b); cout << " c = a " << endl; c = a; cout<<endl; }1. 赋值函数中,上来比较this == &other是很必要的,要防止自身复制,这是很危险的,因为下面有delete []m_data,如果提前把m_data释放了,指针就成了野指针,再赋值就错了。
2. 赋值函数里,紧接着就要释放m_data,否则就没机会了,下边就有新指向了
3. 拷贝构造函数是在对象被创建时调用,赋值函数只能被已经存在了的对象调用
String c = a;调用拷贝构造函数,因为c一开始不存在,最好携程String c(a);
相关文章推荐
- map
- VC++绘图时,利用双缓冲解决屏幕闪烁 转载
- c++ 时间处理
- C语言之static作用
- c++技术系统学习资料
- 图的拓扑排序的非递归和递归的c++实现
- VC++双缓冲保持背景不擦除之实现
- C语言-结构体内存对齐
- c++中的explicit关键字
- 用VS2008的nmake编译(libevent)C语言代码的方法
- C++中随机函数rand()和srand()的用法
- C语言-不同类型数据间的混合运算
- 统计输入字符各个字母出现频率的解题思路
- 七牛(qiniu)C/C++ SDK 实现上传
- (C/C++学习笔记)临时对象深入理解
- 深度探索C++对象模型--Function语意学
- list
- [LeetCode] Reverse Linked List II
- C++为了兼容,所以并不是纯面向对象编程语言
- stack