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;前者通常比较高效,并可以避免切割问题。

 

 

 

 

 


 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值