歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++ 之 值傳遞和引用傳遞

C++ 之 值傳遞和引用傳遞

日期:2017/3/1 9:16:45   编辑:Linux編程

1 值傳遞

值傳遞實際上是,拷貝實參的值傳遞給形參,常用於“小對象” (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 取決於傳遞進來的參數

// basic is type Quote; bulk is type Bulk_quote
print_total(cout, basic, 20); // calls Quote::net_price
print_total(cout, bulk, 20); // calls Bulk_quote::net_price

C++ 的動態綁定機制,使得程序直到運行時,才基於引用或指針綁定的對象類型,來選擇調用哪個虛函數

小結:

直接套用 <C++ Programming Language> 中的建議和 <C++ Primer> 中對動態綁定的解釋

1) use pass-by-value for small objects

2) use pass-by-const-reference to pass large values that you don’t need to modify

3) dynamic binding happens when a virtual function is called through a reference (or a pointer) to a base class

參考資料:

<C++ Programming Language_4th> ch 12.2.1

<Effective C++_3rd> item 20

<C++ Primer_5th> ch 6.2, ch 15.1

Copyright © Linux教程網 All Rights Reserved