牛文共赏
http://blog.csdn.net/ab198604/article/details/19125419
最后一个例子要来回的试,很有意思
个人见解,先谈谈浅拷贝与深拷贝之间的区别,区分它们的最大区别就是在调用完拷贝构造函数后,两个对象之间是否还存在一定的联系,如果两个对象能够完全独立,则说明是深拷贝,否则是浅拷贝。以各种教材的String类的深拷贝实现为例,下面进行说明。
为了实现深拷贝操作,我们需要自己来构建拷贝构造函数,因为我们一旦构建了自己的拷贝构造函数,系统就不再提供默认的拷贝构造函数了。
下面是String.h
- #ifndef _STRING_H_
- #define _STRING_H_
- class String
- {
- public:
- String(char *str=""); //带一个参数的构造函数,可传入参数如“ABC”
- ~String();
- void Display();
- String( const String &other); //拷贝构造函数
- String & operator=(const String &other); //等号赋值运算符重载
- private:
- char *str_; //String需要维护str_数据成员
- char *AllocAndCpy(char *str);
- };
- #endif
下面是String类的具体实现,String.cpp
- #include "String.h"
- #include <cstring>
- #include <iostream>
- using namespace std;
- char *String::AllocAndCpy(char *str) //实施深拷贝的函数
- {
- int len = strlen(str) + 1;
- char *tmp = new char[len];
- memset( tmp, 0, len);
- strncpy(tmp, str, len );
- return tmp;
- }
- String::String( const String & other) /* : str_(other.str_) 这种方式还是浅拷贝*/
- {
- str_ = AllocAndCpy(other.str_); //函数内的实现才是真正的深拷贝,它的处理使得str_与原对象脱离了联系
- }
- String & String::operator=(const String &other)
- {
- if( this == &other)
- {
- return *this;
- }
- //销毁原有空间
- delete [] str_;
- str_ = AllocAndCpy(other.str_);
- return *this;
- }
- String::String( char *str)
- {
- str_ = AllocAndCpy(str);
- }
- String::~String()
- {
- delete [] str_;
- }
- void String::Display()
- {
- cout << str_ << endl;
- }
下面是测试代码,代码中也有详细的注释:
- int main(void)
- {
- String s1("AAA");
- s1.Display();
- String s2 = s1;//调用默认的拷贝构造函数,系统提供的默认拷贝构造函数实施的是浅拷贝s2.str_ = s1.str_;相同于s1,s2两个对象的str_指针指向相同的内存,当两个对象生存期结束时,都要调用析构函数,导致同一块内存被,释放了两次,故而产生错误.解决方法实施深拷贝,自己提供拷贝构造函数
- //等号运算符的重载
- String s3;
- s3.Display();
- s3 = s2; // = 号运算符,它调用的是系统默认的等号运算符,实施的也是浅拷贝,s3.str_ = s2.str_;仍然会出现同一块内存被销毁两次的情况,所以要自己提供等号运算符实施深拷贝。等价于s3.operator=(s2);
- return 0;
- }
下面说明关于禁止拷贝的情形。在某些场合,比如设计模式中有个Singleton单例模式,即一个类只能有一个实例,就是说这个类的对象是要独一无二的,它不允许被拷贝,也不允许赋值,也就是说我们要提供禁止拷贝的功能,以下就是将一个类实施为禁止拷贝的步骤,其实很简单:
(1)将拷贝构造函数与operator=(等号运算符重载函数)均声明为private私有访问权限
(2)在CPP文件中不提供他们的实现
这样,当在主程序进行拷贝复制或赋值操作时,编译将出错,因为它们没有拷贝构造函数或赋值操作的实现。只有声明,而且还是私有的。
下面总结一下,空类默认的成员函数有6个:
- class Empty{}; //这是一个空类。
- Empty(); //默认构造函数
- Empty(const Empty &);//默认拷贝构造
- ~Empty(); //默认析构函数
- Empty & operator=(const Empty &)//默认赋值运算符
- Empty *operator&();//取地址运算符
- const Empty *operator &() const; //取地址运算符const
- #include <iostream>
- using namespace std;
- class Empty
- {
- public:
- Empty * operator&()
- {
- cout << "AAA"<< endl;
- return *this;
- }
- const Empty *operator&() const
- {
- cout << "BBB"<<endl;
- return this;
- }
- };
- int main()
- {
- Empty e;
- Empty *p = &e; //将调用取地址运算符,等价于e.operator&()
- const Empty e2;
- const Empty *p2 = &e2; //调用的是含const的取地址运算符
- //<strong><span style="color:#ff6666;">空类的大小是1个字节</span></strong>,编译器将为它生成一个字生的空间
- cout << sizoef(Empty) << endl;
- return 0;
- }