Effective C++ 详解条款20. 以pass-by-reference-to-const替换pass-by-value

本文讨论了C++中对象作为参数传递时的问题,特别是对象切割现象。通过实例展示了当派生类对象以值传递给只接受基类指针或引用的函数时,会导致派生类特有的行为丢失。为了解决这个问题,推荐使用常量引用传递(pass-by-reference-to-const),这种方式不仅避免对象切割,还能提高效率。此外,总结指出对于内置类型和STL迭代器,仍然推荐使用值传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缺省情况下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更适当。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值