C++ 之 值传递和引用传递

值传递实际上是,拷贝实参的值传递给形参,常用于“小对象” (small objects)

int fact(int val) // factorial of val { int ret = 1; // assign ret * val to ret and decrement val while (val > 1) ret *= val--; return ret; }

调用该函数:

cout << "5! is " << fact(5) << endl;

<Effective C++> 中提及,值传递适用的“小对象”为:内置类型(built-in types),STL迭代器,函数对象类型(function object types)

2  引用传递

引用传递不涉及拷贝,传递给形参的是实参变量的引用,常用来传递“大数值” (large values)

使用引用传递,有两个优点:更高效,防切断

2.1  更高效

下面是 Person 基类,及其派生类 Student 的定义

// class Person and its subclass Student 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; };

现有一个验证学生身份的函数,形参为值传递,则拷贝实参给形参的代价是:调用基类 Person 的构造函数一次,基类内 string 型数据成员的构造函数两次,

派生类 Student 的构造函数一次,派生类内 string 型数据成员两次,最后还会调用相应的析构函数六次,共计十二次调用,自然效率低下。

而使用引用传递,并不涉及拷贝操作,故而显著的提高了效率。

// 1) pass-by-value bool validateStudent(Student s); // 2) pass-by-reference-to-const bool validateStudent(const Student& s);

2.2  防切断

下面的例子中,派生类 WindowWithScrollBars 中,重写了基类 Window 的虚函数 display

// base class Window
class
Window{ public: std::string name() const; // return name of window virtual void display() const; // draw window and contents }; class WindowWithScrollBars : public Window { public: virtual void display() const; };

printNameAndDisplay 函数中,调用了 dispaly 函数,而形参若采用值传递方式,则会发生“切断” (slicing),即 wwsb 调用的是 Window::display()

// pass-by-value is incorrect void printNameAndDisplay(Window w) { std::cout << w.name(); w.display(); } // WindowWithScrollBars object will be sliced off WindowWithScrollBars wwsb; printNameAndDisplay(wwsb);

因为在 printNameAndDisplay 中,并不修改传递进来的参数。因此,可使用 pass-by-const-reference 的形式,避免“切断”的发生

3  动态绑定

上面"切断"的例子,实际上涉及的是 C++ 的动态绑定机制 (dynamic binding), 而动态绑定的一个关键点就是引用传递,下面看个更形象的例子:

class Quote { public: std::string isbn() const; virtual double net_price(std::size_t n) const; }; // Bulk_quote inherits from Quote class Bulk_quote : public Quote { public: double net_price(std::size_t) const override; };

 

在 print_total 函数中,需要调用 net_price,采用 pass-by-const-reference 形式

// calculate and print the price double print_total(ostream &os, const Quote &item, size_t n) { double ret = item.net_price(n); return ret; }

实际程序中,调用 Quote::net_price 还是 Bulk_quote::net_price 取决于传递进来的参数

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/438183a41b5110b8bcb86e1a00765ca5.html