赋值运算符函数
对于定义一个赋值运算符函数时,需要注意一下几点:
(1)函数的返回类型必须是一个引用,因为只有返回引用,才可以连续赋值
(2)传入的参数声明为常量引用,可以提高代码效率,同时赋值运算函数内不会改变传入的实例状态
(3)一定要记得释放实例自身已有的内存,否则程序容易出现内存泄露
(4)注意传入的参数和当前的实例是不是同一个实例,如果是同一个,则不用进行赋值操作,直接返回即可。
复制构造函数
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是复制构造函数。
什么时候调用复制构造函数?
(1)当用类的一个对象初始化该类的另一个对象时;
(2)将一个对象作为实参传递给一个非引用类型的形参时;
(3)从一个返回类型为非引用类型的函数返回一个对象时;
深拷贝和浅拷贝的区别:
1. 默认拷贝构造函数
很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:
Rect::Rect(const Rect& r) { width = r.width; height = r.height; }
2. 浅拷贝
所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了。
当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。
3. 深拷贝
在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:
深拷贝主要解决的问题是指针成员变量浅拷贝的问题。
1. 防止默认拷贝(也能够禁止复制)
有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。如下程序:
#include <iostream> using namespace std; class CExample { private: int value; public: //构造函数 CExample(int val) { value = val; cout << "creat: " << value << endl; } private: //拷贝构造,只是声明 CExample(const CExample& C); public: ~CExample() { cout << "delete: " << value << endl; } void Show() { cout << value << endl; } }; //全局函数 void g_Fun(CExample C) { cout << "test" << endl; } int main() { CExample test(1); // g_Fun(test); // 按值传递将出错 return 0; }
而根据《C++ Primer》第四版13.1.3节,要禁止类的复制, 类必须显示声明其复制构造函数为private。
小问题:一个类中可以有多个拷贝构造函数吗?
解答:类中可以存在超过一个拷贝构造函数。
1 class X {
2 public:
3 X(const X&); // const 的拷贝构造
4 X(X&); // 非const的拷贝构造
5 };
关于拷贝构造函数与拷贝赋值操作符的区别:
两都都是用已存在的对象A来初始化另一个对象B。不同之处在于:
复制构造函数是针对一个未存在的对象进行初始化;赋值是针对已存在的对象进行初始化。
#include<iostream> #include<cstring> using namespace std; class CMyString { private: //int value; char *m_pdata; public: CMyString(char *pdata=NULL); CMyString(const CMyString &str);//复制构造函数 CMyString & operator = (const CMyString &str);//赋值运算符函数 ~CMyString(void); void print(); }; CMyString::CMyString(char *pdata) { if(pdata==NULL) { m_pdata=new char[1]; m_pdata[0]='