避免浪费时间空间
默认情况下,C++的函数调用是传值调用,也就是说形参拷贝实参的内容。考虑以下继承体系:
class Person
{
private:
string name;
string address;
public:
Person(){}
virtual ~Person(){}
};
class Student: public Person
{
private:
string schoolName;
string schoolAddress;
public:
Student(){}
~Student(){}
};
假设有个函数接口:
void PrintStudent(Student ss);
那么如果这样调用:
Student s;
PrintStudent(s);
形参ss就会把实参s完完整整地复制一遍,这其中先后调用了Person的构造函数和Student的构造函数,而每个类中又包含两个string对象,所以总共会调用6次构造函数(4个string构造、Person构造和Student构造,注意这里的构造包括构造函数和拷贝构造函数),相应也会调用6次析构函数(注意当有派生关系存在时,基类的析构函数应该声明成虚的,这个在条款七中提到过)。
实际上,在PrintStudent里面其实只是打印Student的信息,并没有对这个对象做出修改,所以完整的拷贝显然既浪费时间,又浪费空间。如果你习惯使用C,那么会想到把形参作成指针,这样拷贝只是拷贝一个指针的内容而已,像下面这样:
void PrintStudent(Student* ss);//声明
PrintStudent(&s); //调用
或者也可以使用引用:
void PrintStudent(Student& ss);//声明
PrintStudent(s); //调用
就可以了,引用在原来代码的基础上只是多加了一个&,看上去比指针更自然,这算是C++的一个优点吧,在函数体中也可以避免对指针的操作,从而减少出错的可能性。
避免对象切割问题
以by reference方式传递参数也可以避免slicing(对象切割)问题。当一个派生类对象以by value方式传递并被视为一个base class对象,base class的copy构造函数会被调用,而“造成此对象的行为像个派生类对象”的那些特化性质全被切割掉了,仅仅留下一个base class对象。
总结
尽量以pass-by-reference-to-const来代替pass-by-value,前者通常比较高效,并可以避免切割
以上规则并不适用于内置类型、STL迭代器和函数对象,对它们而言,pass-by-value是更好的选择