考虑以下代码
class Person {
public:
Person();
virtual ~Person(); //条款7
//...
private:
std::string name;
std::string address;
};
class Student : public Person {
public:
Student();
~Student();
//...
private:
std::string schoolName;
std::string schoolAddresss;
};
然后有以下函数调用:
bool validateStudent(Student s);
Student plato;
bool platoIsOK = validateStudent(plato);
validateStudent
函数参数传递成本为:一次Student 拷贝构造函数调用(C++ Primer Page:441),一次Student析构函数调用(validateStudent返回时s会被销毁);同时也要注意Student
对象内有两个string对象,所以每构造一个Student对象也就构造了两个string对象;此外Student对象继承自Person对象.所以每次构造Student对象也必须构造出一个Person对象;最终这个以by value方式传递一个Student对象,成本是"六次构造函数和六次析构函数"
回避所有那些构造和析构动作的办法就是pass by reference-to-const
bool validateStudent(const Student&s);
这种传递方式效率要高得多,没有任何构造函数或析构函数被调用,因为没有任何新对象被创建;
同时by reference方式传递参数也可以避免slicing(对象切割)问题;考虑以下代码
class window {
public:
//...
std::string name() const;
virtual void display const;
};
class WindowWithScrollBars : public Window {
public:
//...
virtual void display() const;
};
现在你希望写个函数打印窗口名称:
void printNameAndDisplay(Window w) { // 不正确,参数可能被切割
std::cout << w.name();
w.display();
}
进行如下调用:
WindowWithScrollBars wwsb;
printNameAndDisplay(wwsb);
参数w会被构造成一个Window对象,所以再PrintNameAndDiaplay内调用display总是Window::display;解决办法就是以by reference-to-const传递w
void printNameAndDisplay(const Window& w) { // 不正确,参数可能被切割
std::cout << w.name();
w.display();
}
但是如果你有个对象属于内置类型(如int),pass by value往往比pass by reference的效率高些;这个忠告也适用与STL的迭代器和函数对象,因为习惯上它们都被设计为passed by value;
一般而言,你可以合理假设"pass by value"开销不大的唯一对象就是内置类型和STL的迭代器和函数对象,至于其他任何东西尽量以pass-by-reference-const替换pass-by-value