effective C++ 读书笔记 条款12

条款12 : 复制对象时不要忘记其每一个成分

编写一个类用来表现顾客,其中手动写出copying函数使得外界对它们的调用记录会被logged下来:

#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
	cout<<funcName<<endl;
}

class Customer
{
public:
	Customer()
	{

	}
	Customer(const Customer& rhs);
	Customer& operator= (const Customer& rhs);

private:
	string name;
};

Customer::Customer(const Customer& rhs)
{
	this->name = rhs.name;
	logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
	logCall("赋值操作符重载");
	name = rhs.name;
	return *this;
}
int main()
{
	Customer c1;
	Customer c2(c1);
	Customer c3;
	c3 = c2;
	return 0;
}

上面的函数看起来没有问题,知道一个新的成员变量加入:

#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
	cout<<funcName<<endl;
}
class Date
{
};
class Customer
{
public:
	Customer()
	{
	}
	Customer(const Customer& rhs);
	Customer& operator= (const Customer& rhs);

private:
	string name;
	Date data; //这里增加一个成员变量

};
Customer::Customer(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	this->name = rhs.name;
	logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	logCall("赋值操作符重载");
	name = rhs.name;
	return *this;
}
int main()
{
	Customer c1;
	Customer c2(c1);
	Customer c3;
	c3 = c2;
	return 0;
}
/*
如果你为一个class添加一个成员变量,你必须同时修改copying函数,如果你忘记,
编译器是不会给出任何提示的。

*/

上面说明:如果你为一个class添加一个成员变量,你必须同时修改copying函数

现在让他拥有子类:

#include <iostream>
#include <string>
using namespace std;

void logCall(const string funcName)
{
	cout<<funcName<<endl;
}

class Date
{

};
class Customer
{
public:
	Customer()
	{

	}
	Customer(const Customer& rhs);
	Customer& operator= (const Customer& rhs);

private:
	string name;
	Date data; //这里增加一个成员变量

};

Customer::Customer(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	this->name = rhs.name;
	logCall("拷贝构造函数");
}

Customer& Customer::operator=(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	logCall("赋值操作符重载");
	name = rhs.name;
	return *this;
}

//现在发生了继承
class PriorityCustomer:public Customer
{
public:
	PriorityCustomer(const PriorityCustomer& rhs);
	PriorityCustomer& operator= (const  PriorityCustomer& rhs);

private:
	int priority;
};

PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):priority(rhs.priority)
{
	logCall("PriorityCustomer copy constructor");
}
PriorityCustomer& PriorityCustomer::operator =(const PriorityCustomer& rhs)
{
	logCall("PriorityCustomer copy assignment operator");
	priority = rhs.priority;

	return *this;
}
/*

  PriorityCustomer的copying函数看起来好像复制了PriorityCustomer内的每一样东西,但是仔细看就会发现,
  它们复制了PriorityCustomer声明的成员变量,但是每个PriorityCustomer还内含它所继承的Customer成员变
  量复件(副本),而这些成员变量却没有被复制。priorityCustome的copy构造函数并没有制定实参传给其base
  class构造函数(也就是说它在它的成员初值列表中没有提到Customer),因此PriorityCustomer对象的Customer
  成分会被不带实参的Customer构造函数初始化,那么也就是说Customer内的成员变量name和data将执行缺省的初始化。

*/

int main()
{

	Customer c1;
	Customer c2(c1);
	Customer c3;
	c3 = c2;
	return 0;
}
/*

*/

子类的copy函数只是复制了子类本身加上去的成员变量,但是继承下来的成员变量却没有没复制,怎么解决?

#include <iostream>
#include <string>
using namespace std;

void logCall(const string funcName)
{
	cout<<funcName<<endl;
}

class Date
{

};
class Customer
{
public:
	Customer()
	{

	}
	Customer(const Customer& rhs);
	Customer& operator= (const Customer& rhs);

private:
	string name;
	Date data; //这里增加一个成员变量

};

Customer::Customer(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	this->name = rhs.name;
	logCall("拷贝构造函数");
}

Customer& Customer::operator=(const Customer& rhs)
{
	//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
	logCall("赋值操作符重载");
	name = rhs.name;
	return *this;
}

/*
任何时候,只要我们为子类编写copy函数,那我们就必须小心复制其base class成分,而这些成分一般都是private;
所以我们无法直接访问他们,我们能做的就是让子类的copying函数调用相应的base class函数:
*/
class PriorityCustomer:public Customer
{
public:
	PriorityCustomer(const PriorityCustomer& rhs);
	PriorityCustomer& operator= (const  PriorityCustomer& rhs);

private:
	int priority;
};

//我们能做的就是让子类的copying函数调用相应的base class函数:
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)//调用base class的copy构造函数
{
	logCall("PriorityCustomer copy constructor");
}
//我们能做的就是让子类的copying函数调用相应的base class函数:
PriorityCustomer& PriorityCustomer::operator =(const PriorityCustomer& rhs)
{
	logCall("PriorityCustomer copy assignment operator");
	Customer::operator =(rhs); //对base class成分进行赋值动作
	priority = rhs.priority;

	return *this;
}

int main()
{

	Customer c1;
	Customer c2(c1);
	Customer c3;
	c3 = c2;
	return 0;
}
/*

*/

我们能做的就是让子类的copying函数调用相应的base class函数

总结:

1:Copying函数应该确保复制“对象内的所有成员变量”及所有base class成分

2:不要尝试以某个copying函数实现另外一个copying函数。应该讲共同的机能放进第三个函数当中,并由两个copying函数共同调用。

时间: 2024-10-22 15:42:47

effective C++ 读书笔记 条款12的相关文章

effective C++ 读书笔记 条款12与条款13

条款12:确定你的public继承塑膜出is-a关系: 这个条款主要将了一些特殊情况:比如企鹅是鸟,企鹅可以继承于鸟,但是鸟会飞,企鹅却不能飞:还有让正方形继承矩形可能也会造成这种尴尬! 这个问题以前想过,但是不知道怎么解决,如果现实生活当中确实要这么使用:比如 猫 狗 鱼  猪等等许多动物继承Animal类,但是猫狗等不会游泳, 假如这里是有很多动物,不能采用鱼里面专门加一个方法!  这个现在还没想出来,条款12也没有讲如果要这么用该怎么处理就是将要避免这样. is - a; 在面向对象程序设

effective C++ 读书笔记 条款06

条款06:若不想使用编译器自动生成的函数,就该明确拒绝: 直接看代码与注释: #include <iostream> using namespace std; class Test { public: Test() { } ~Test() { } /* void TT() { Test t1; Test t2(t1); } */ private: Test(const Test& test); Test& operator = (const Test& test); }

Effective C++读书笔记(条款11-17)

继续上一篇... (二).构造/析构/赋值运算 ____________________________________________________________________________________________________________________________________ 条款11:在operator= 中处理 "自我赋值" #1.确保当对象自我赋值时 operator=有良好行为.其中包括"自我赋值安全性"和 "异

Effective C++读书笔记(条款18-23)

(四).设计与声明 ____________________________________________________________________________________________________________________________________ 条款18:让接口容易被使用,而不容易被误用 #1.导入新类型可以让接口不易被误用,以函数替换对象则可以保证类型安全性. 例如: class Date{ public: Date(int month, int day

Effective C++读书笔记(条款24-29)

Effective C++第四篇,扩展的有点多... (四).设计与声明 ____________________________________________________________________________________________________________________________________ 条款24:若所有参数皆需类型转换,请为此采用non-member函数 #1.如果你需要为某个函数的所有参数(包括被 this指针所指的那个隐喻参数)进行 类型转

Effective C++读书笔记(条款1-10)

不得不说,Effective C++确实是一本C++进阶的好书,刚浏览完第二遍, 现对其做一个大体性的总结 ,并进行适当的展开,作为以后C++参考复习之用. (一).让自己习惯C++ ____________________________________________________________________________________________________________________________________ 条款1:视C++为一个语言联邦 #1.将C++ 分

effective C++ 读书笔记 条款21

条款21 :必须返回对象时,别妄想返回其reference 条款20里面虽然说传引用比传值好用,但是不能传递一些 reference指向其实并不存在的对象 上代码: #include <iostream> using namespace std; class Rational { public: // Rational() // { // } Rational(int m = 0, int n = 0 ) { } ~Rational() { } private: int n, d; /* 运算

effective C++ 读书笔记 条款20

条款20:宁以 pass-by-reference-to-const 替换 pass -by -value 1:采用后者效率高:看代码: #include <iostream> using namespace std; class Person { public: Person() { cout<<"Person()"<<endl; } Person(const Person& p) { cout<<"Person(co

effective C++ 读书笔记 条款11

条款11: 在operator= 中处理"自我赋值" 在实现operator=时考虑自我赋值是必要的就像 x=y .我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指针更恰当一点). 例如以下 第一版: #include <iostream> using namespace std; class bitmap { public: bitmap() { cout<<"调用bitmap()无參构造函数"<<endl; }