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(const Person& p)"<<endl;
	}
	virtual ~Person()
	{
		cout<<"~Person()"<<endl;
	}

private:
	string name;
	string address;
};

class Student:public Person
{
public:
	Student()
	{
		cout<<"Student()"<<endl;
	}
	Student(const Student& p)
	{
		cout<<"Student(const Student& p)"<<endl;
	}
	virtual ~Student()
	{
		cout<<"~Student()"<<endl;
	}
private:
	string schoolName;
	string schoolAddress;
};

void Print(Student s)
{

}

int main()
{

	Student stu;
	Print(stu);
	return 0;
}

/*

Student stu;
Print(stu);
当调用上面的函数时,Student的copy构造函数会被调用,以stu为蓝本讲s初始化,函数结束时,
s会被销毁,因此参数的传递成本是 一次Student copy构造函数调用,加上一次student析构函数调用

Person 有两个String 对象
Student 有两个String对象

所以上面参数的传递成本要加上 4个String的构造函数与析构函数

同样,一次Student构造函数调用,必然Person的构造函数调用
这样下来,上面传递的成本总共是: 六次构造函数和六次析构函数

effective C++ 条款20 当中说 这里会 调用 Student的 copy 构造函数 和 Person的 copy构造函数,我这里实验
调用Student的copy 构造函数,但是不会调用Person的 copy 构造函数;
这个我单独编写了一个程序证明我的是对的,调用的是子类的copy构造函数,不会调用父类的copy构造函数。

综上来说,这么传递的效率太低。

*/

这个我单独编写了一个程序证明我的是对的,调用的是子类的copy构造函数,不会调用父类的copy构造函数。

看代码:

#include <iostream>

using namespace std;

class Parent
{
public:
	Parent()
	{
		cout<<"调用父类的无参构造函数"<<endl;
	}
	Parent(const Parent& p)
	{
		cout<<"父类的copy 构造函数"<<endl;
	}
	~Parent()
	{

	}
};

class Children:public Parent
{
public:
	Children()
	{
		cout<<"调用子类的无参构造函数"<<endl;
	}
	Children(const Children& c)
	{
		cout<<"子类的copy 构造函数"<<endl;
	}
	~Children()
	{

	}
};

int main()
{
	Children aa;
	Children bb(aa);
/*
调用父类的无参构造函数
调用子类的无参构造函数

调用父类的无参构造函数
子类的copy 构造函数
*/

return 0;
}

上面代码说明了  子类对象调用copy构造函数构造对象的时候,不会调用父类的copy构造函数,而是调用的父类的普通构造函数。

2:后者避免对象切割问题;看代码:

#include <iostream>

using namespace std;

class Base
{
public:
	Base()
	{
		cout<<"调用父类的构造函数"<<endl;
	}
	Base(const Base& b)
	{
		cout<<"调用的是父类的copy 构造函数"<<endl;
	}
	~Base()
	{

	}

	virtual void display() const
	{
		cout<<"调用的是父类的display函数"<<endl;
	}
private:
	int i;
};

class Derived : public Base
{
public:
	Derived()
	{
		cout<<"调用子类的构造函数"<<endl;
	}
	~Derived()
	{

	}

	virtual void display() const
	{
		cout<<"调用的是子类的display函数"<<endl;

	}

};

void print(Base b)
{
	b.display();//参数被切割 即使传递子类对象,调用的也是父类的display函数
}

void print2(const Base& b)
{
	b.display();
}
int main()
{

	Derived aa;
	print(aa); //这里调用了 父类的copy构造函数 父类的print函数;

	print2(aa);
	return 0;
}
/*
以值传递的方式传递

  上面说的一个缺点是:效率低下

  下面再说另外一个缺点:对象切割问题

	  void print(Base b)
	  {
		b.display();//参数被切割 调用的是父类的函数
	  }
	  Derived aa;
	  print(aa);

  aa为子类,Print的参数为基类
  当一个子类的对象以值传递方式传递并被视为一个基类对象,基类的copy 构造函数会被调用,而“造成此对象的行为像个子类对象”的
  那些特化性质完全被切割掉了,仅仅留下以一个基类对象。发生了参数切割。

  采用引用传值可以解决这个问题。
*/

所以  以值传递方式 子类赋给父类的时候会发生对象切割,采用引用代替他。

总结一句话:

尽量以pass-by-reference-to-const 替换 pass -by -value;前者通常比较高效,并可以避免切割问题。

时间: 2024-10-03 14:55:49

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

&lt;&lt;Effective c++&gt;&gt;读书笔记---条款20:宁以pass-by-reference-to-const替换pass-by-value

尽量以pass-by-reference-to-const替换pass-by-value.前者通常比较高效,因为它可以避免调用拷贝构造函数和析构函数,并且可以避免切割问题.一下是一个很好的切片问题实例: class A { public: A() {} virtual ~A() {} virtual void Display() { cout << "A::Display()" << endl; } }; class B : public A { public:

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++读书笔记(条款18-23)

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

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++读书笔记(条款24-29)

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

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

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

effective C++ 读书笔记 条款11

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

effective C++ 读书笔记 条款08

条款08  别让异常逃离析构函数: 假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去) 看代码: #include <iostream> using namespace std; class DBConnection { public: void close() { int i = 3; int j = 0; int k = i/j; printf("%d\n",k); } }; class DBConn { public: DBC

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

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