缺省情况下C++以by value方式传递对象至函数,但pass by reference to const没有任何构造函数或析构函数被调用,因为没有任何新对象被创建,没有任何对象被调用,所有效率更高。
以by reference方式传递参数也可以避免对象切割问题。
当一个derived class对象以by value方式传递并被视为一个base class对象,base class的copy构造函数会被调用,而“造成此对象的行为像个derived class对象”的那些特化性质全被切割掉了,仅仅留下一个base class对象。因为正是base class构造函数建立了它。但这几乎绝不会是你想要的。
假设你在一组classes 上工作,用来实现一个图形窗口系统:
class window {
public:
...
std::string name () const; //返回窗口名称
virtual void display () const; //显示窗口和其内容
};
class windowwithscrollBars: public window {
public:
...
virtual void display () const;
};
所有window
对象都带有一个名称,你可以通过name
函数取得它。所有窗口都可显示,你可以通过display
函数完成它。
现在假设你希望写个函数打印窗口名称,然后显示该窗口。下面是错误示范:
void printNameAndDisplay (window w) //不正确!参数可能被切割。
{
std::cout<<w.name ();
w.display ();
}
当你调用上述函数并交给它一个 windowWithScrollBars
对象,会发生什么事呢?
windowwithScrollBars wwsb;
printNameAndDisplay (wwsb) ;
参数w
会被构造成为一个window
对象;它是passed by value。而造成wwsb
“之所以是个windowWithScrollBars
对象”的所有特化信息都会被切除。在printNameAndDisplay
函数内不论传递过来的对象原本是什么类型,参数w
就像一个window
对象(因为其类型是window
)。因此在printNameAndDisplay
内调用display
调用的总是 window :: display
,绝不会是 windowWithScrollBars::displayo
.
解决切割问题的办法,就是以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更适当。