我们随意写一个空的类,它可能并不像你看到的那样是"空"的,C++会为你做一些事情,看看下面这个类:
class NiaoShu {};
写完这个类之后,C++会为这个类自动生成以下内容:默认构造函数,拷贝构造函数,析构函数等等:
class NiaoShu
{
public:
NiaoShu() {}; //默认构造
NiaoShu(const NiaoShu& rhs) {} //拷贝构造
~NiaoShu() {}; //析构
NiaoShu& operator=(const NiaoShu& rhs) {} //拷贝赋值操作符
};
如果没有定义拷贝赋值构造函数,而在其他地方调用了这种构造函数,编译器将无法确定怎么赋值,看看这面这个类:
template<class T>
class Example1
{
public:
Example1(std::string& name, const T& value) :m_name(name),
m_value(value)
{
}
~Example1()
{
}
void func()
{
std::cout << m_name.c_str() << std::endl;
}
private:
std::string& m_name;
T m_value;
};
int main()
{
std::string name1 = "niaoshu1";
std::string name2 = "niaoshu2";
Example1<int> e1(name1,4);
Example1<int> e2(name2,5);
e1 = e2; //Error
e1.func();
e2.func();
}
此时编译器将无法编译通过,此时,我们需要加上拷贝赋值构造函数:
......
Example1& operator=(Example1& rhs)
{
this->m_name = rhs.m_name;
this->m_value = rhs.m_value;
return *this;
}
......
结合上述代码,此时实际上是将e1的引用m_name所指的对象被赋值为e2的对象所指的内容,上述func的输出结果为:
niaoshu2
niaoshu2
请按任意键继续. . .
我们知道,通过编译器新建一个类的时候,编译器会为你自动生成拷贝函数,尽管这个拷贝函数你看不到,但是它确实存在。而有的时候,我们希望能够自己写Copying函数,这时候,我们只需要明确地在代码中写出来就好,但是不够细心的程序员可能会给他的代码带来一些安全隐患,看看以下的代码:
//基类
class CBase
{
public:
......
CBase(const CBase& rhs);
virtual ~CBase();
public:
int m_iChannel;
};
CBase::CBase(const CBase& rhs)
:m_iChannel(rhs.m_iChannel)
{
}
//派生类
class CSon1 : public CBase
{
public:
......
CSon1(const CSon1& rhs);
virtual ~CSon1();
public:
int m_iIndex;
};
CSon1::CSon1(const CSon1& rhs)
:m_iIndex(rhs.m_iIndex)
{
}
CSon1看起来好像复制了CBase的每个成员,但我们仔细观察一下,有CSon1继承自CBase的每一个成员变量副本没有得到初始化,CSon1的Copy构造函数并没有指定实参传递给CBase。此时,我们需要对Copy构造函数做如下修改:
CSon1::CSon1(const CSon1& rhs)
:CBase(rhs),
m_iIndex(rhs.m_iIndex)
{
}
即在程序的继承体系中,我们在重写Copy构造函数的时候,需要让派生类的copying函数调用相应的基类函数。