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