首页 > 代码库 > 条款22: 尽量用“传引用”而不用“传值”
条款22: 尽量用“传引用”而不用“传值”
c语言中,什么都是通过传值来实现的,c++继承了这一传统并将它作为默认方式。除非明确指定,函数的形参总是通过“实参的拷贝”(拷贝构造函数)来初始化的,函数的调用者得到的也是函数返回值的拷贝。为避免这种潜在的昂贵的开销,就不要通过值来传递对象,而要通过引用。
通过引用来传递参数还有另外一个优点:它避免了所谓的“切割问题(slicing problem)”。当一个派生类的对象作为基类对象被传递时,它(派生类对象)的作为派生类所具有的行为特性会被“切割”掉,从而变成了一个简单的基类对象。这往往不是你所想要的。例如,假设设计这么一套实现图形窗口系统的类:
class window {public: string name() const; // 返回窗口名 virtual void display() const; // 绘制窗口内容};class windowwithscrollbars: public window {public: virtual void display() const;};
现在假设写一个函数来打印窗口的名字然后显示这个窗口。下面是一个用错误的方法写出来的函数:
// 一个受“切割问题”困扰的函数void printnameanddisplay(window w){ cout << w.name(); w.display();}
想象当用一个windowwithscrollbars对象来调用这个函数时将发生什么:
windowwithscrollbars wwsb;printnameanddisplay(wwsb);
参数w将会作为一个windows对象而被创建(它是通过值来传递的,记得吗?),所有wwsb所具有的作为windowwithscrollbars对象的行为特性都被“切割”掉了。printnameanddisplay内部,w的行为就象是一个类window的对象(因为它本身就是一个window的对象),而不管当初传到函数的对象类型是什么。尤其是,printnameanddisplay内部对display的调用总是window::display,而不是windowwithscrollbars::display。
解决切割问题的方法是通过引用来传递w:
// 一个不受“切割问题”困扰的函数void printnameanddisplay(const window& w){ cout << w.name(); w.display();}
现在w的行为就和传到函数的真实类型一致了。
以上说的其实就是多态的实现,参数是基类的指针或引用,实际运行的对象类型在运行时决定。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。