Effective C++ 条款12:复制对象时勿忘其每一个成分(重要且常用的条款)_copying函数-CSDN博客
这篇文章写的很好,例子也很完整,但是对于文中的坑二,我难以理解作者想表达的意思,于是自己再做一点补充说明。
Son(const Son& s) : m_score(s.m_score)
{
Base::Base(s);//在一个copying函数中去调用另一个copying函数
cout << "this is Son class copy 拷贝函数" << endl;
}
文中说:
这里虽然也调用了Base class 的copy 构造函数,但是这里是把Son的copy构造函数内去调用的Base::Base(s);中的s当做是一个已经存在了的对象,把它里面的Base class 成分赋值给自己的Base class 成分,这不就是自己赋值 给自己嘛,本来自己Son3就没初始化,还有用自己的Base class成分给自己赋值一遍,这显然不会如你所愿!
或者,你可以这样理解,因为这里Son的copy 构造函数中,传入的参数是const Son& s
有引用的类型,因此你不能再让s赋值为别人(也包括s赋值为自己),也即对于引用类型而言,因为为引用必须在定义的时候初始化,并且不能重新赋值。
----------------------------------------------------------------------------------------------------------------------
在我看来,其实就是一个时机的问题。在这段代码中,子类构造函数中没有显式调用Base类的构造函数,但是子类构造之前一定是需要调用父类的构造函数的!所以系统默认调用了父类的无参数构造函数,因此父类中的参数都是随机值。
而在子类的拷贝构造函数体内显式地调用Base::Base(s),这压根无法对真正的父类产生影响,而且出了这个函数体就销毁了。甚至我们可以写成(改动处见 // **************)
#include<iostream>
using namespace std;
#include<string>
class Base
{
public:
Base() {}//默认构造
Base(int age, string name) :m_Age(age), m_Name(name)
{
cout << "this is base class 构造函数" << endl;
};
Base(const Base& b)
{
this->m_Age = b.m_Age;
this->m_Name = b.m_Name;
cout << "this is base class copy 构造函数" << endl;
}
Base& operator=(const Base& b)
{
this->m_Age = b.m_Age;
this->m_Name = b.m_Name;
cout << "this is base class copy assignment 函数" << endl;
return *this;
}
void showInfo()
{
cout << "分数:" << "Ignore" << "\t年龄:" << this->getAge() <<
"\t姓名:" << this->getName() << endl;
}
int& getAge()
{
return this->m_Age;
}
string& getName()
{
return this->m_Name;
}
private:
int m_Age;
string m_Name;
};
Base b; // ********
class Son :public Base
{
public:
Son() {}//默认构造
Son(double sco, int age, string name) :m_score(sco), Base(age, name)
{
cout << "this is Son class 构造函数" << endl;
};
Son(const Son& s) :m_score(s.m_score)
{
b = Base::Base(s); // **********
cout << "this is Son class copy 构造函数" << endl;
}
Son& operator=(const Son& s)
{
this->m_score = s.m_score;
Base::operator=(s);
cout << "this is Son class copy assignment 函数" << endl;
return *this;
}
void showInfo()
{
cout << "分数:" << this->m_score << "\t年龄:" << this->getAge() <<
"\t姓名:" << this->getName() << endl;
}
private:
double m_score;
};
void test()
{
Son s1(404.0, 32, "lzf");
Son s3(s1);
cout << "s1的Info:" << endl;
s1.showInfo(); // 404 32 lzf
cout << "s3的Info:" << endl;
s3.showInfo(); // 404 -858993460 ???
cout << "b的Info:" << endl; // ***********
b.showInfo(); // Ingore 32 lzf
}
int main(void)
{
test();
system("pause");
return 0;
}
所以,归根结底,我觉得还是时机的问题:
因为没有在一开始就调用父类的构造函数,而后面函数体内由于作用域不同根本无法修改到真实的父类构造函数!所以读取出错。
拷贝赋值函数不受影响的原因就是他本质上属于赋值,而不是构造。不需要在最初就执行,后面通过赋值可以改变内部成员变量。