1. 值传递通常要比引用传递的代价昂贵得多。例如下面例子,
点击(此处)折叠或打开
- class Person {
- public:
- Person();
- virtual ~Person();
- //...
- private:
- std::string name;
- std::string address;
- };
- class Student: public Person {
- public:
- Student();
- ~Student();
- //..
- private:
- std::string schoolName;
- std::string schoolAddress;
- };
- //consider codes bellow, what will happen?
- bool validateStudent(Student s);
- Student plato;
- bool platoIsOK = validateStudent(plato);
毫无疑问, Student的copy构造函数将被调用,以plato为蓝本将s进行初始化。当validateStudent返回s会被销毁。此种模式总共分别有6次构造和析构函数的调用(Student,Person,4个String)。
倘若以引用传递
bool validateStudent(const Student& s);
这种方式的效率要高得多:没有任何构造函数或析构函数被调用,因为没有新对象被创建。所以const限制了对象不能被修改。
2. by reference方式传递参数也可以避免对象切割问题。
当一个derived类对象以by value方式传递并被视为一个base类对象,base class基类的copy构造函数会被调用,而“derived class对象特性”将被切割,仅仅留下一个基类对象。
点击(此处)折叠或打开
- 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的对象,是pass by value。而wwsb是
WindowWithScrollBars对象,传入后所有类WindowWithScrollBars的特性化信息都被丢失。因此,这里的wwsb被完全看作一个Window对象,其内部调用的
Window::display()而不是WindowWithScrollBars::display()。
为解决切割问题,需使用by reference to const的方式传递w:
点击(此处)折叠或打开
- void printNameAndDisplay(const Window& w) //很好! 参数不会被切割
- {
- std::cout << w.name();
- w.display();
- }
现在,传进来的窗口是什么类型,w就表现出哪种类型。
**尽量以pass-by-reference-to-const替换pass-by-value。通常前者高效,且可避免切割问题。
**以上规则并不适用于内置类型,以及STL的迭代器和函数对象。对这些而言,pass-by-value往往比较合适。