条款20:宁以pass-by-reference-to-const替换pass-by-value
生活随笔
收集整理的這篇文章主要介紹了
条款20:宁以pass-by-reference-to-const替换pass-by-value
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
條款20:寧以pass-by-reference-to-const替換pass-by-value
缺省情況下C++是以by value 傳遞的。其副本是對象本身的copy 構造函數自動調用的。
class Persion { private:std::string m_name;std::string m_addr; };class Student : public Persion { private:std::string m_schoolName;std::string m_schoolAddr; };bool IsValidStudent(Student s) {return true;} 調用 Student s1;bool b_s = IsValidStudent(s1);?? ? ? IsValidStudent函數調用行為如下:編譯器調用student拷貝構造函數拷貝實參到形參,然后形參使用完后再調用析構函數,但該類調用遠不止這些,如student的父類也需要調用拷貝構造函數,而persion中有兩個string成員也需要調用拷貝構造函數,還有student也有兩個string成員需要調用拷貝構造函數,而且這些調用完后還需要調用析構函數。就因為一個pass-by-value操作,而需要花費這么多成本。
pass-by-reference-to-const
將上面的IsValidStudent函數修改如下 bool IsValidStudent(const Student &s) {return true;}這樣沒有調用任何的構造函數和析構函數,形參實際是實參的副本,因此需要加上const保護實參免修改。 對象切割
? ? ? ? 當一個derived class對象以pass-by-value的形式傳遞給一個base-class對象時,base-class會調用拷貝構造函數,且會把derived class的所有行為都切割掉,即編譯器只當成base-class處理。如果用reference和指針,可以防止對象切割。 class Persion { public:Persion(const string &name, const string& addr) : m_name(name), m_addr(addr) {}virtual ~Persion() {} //作為基類,需要定義虛析構函數string GetName() const {return m_name;}string GetAddr() const {return m_addr;}virtual void DisPlay() {cout<<"Person\n";} private:std::string m_name;std::string m_addr; };class Student : public Persion { public:Student(const Persion &persion, const string &sName, const string &sAddr):Persion(persion.GetName(), persion.GetAddr()),m_schoolName(sName),m_schoolAddr(sAddr){}string GetName() const {return m_schoolName;}virtual void DisPlay() {cout<<"Student\n";} private:std::string m_schoolName;std::string m_schoolAddr; };void DisPlayPersion(Persion persion) {std::cout<<persion.GetName()<<endl;persion.DisPlay(); }調用
Persion p("cuancuan", "guangzhou");Student s1(p, "shiyan", "yuexiu");DisPlayPersion(s1);輸出 cuancuan
Person 結果很明顯,沒有調用student的Display函數 修改函數接口參數為pass-by-reference-to-const void DisPlayPersion(const Persion &persion) 同樣調用結果如下 cuancuan
Student
? ? ? ?看到結果,是不是有一種多態性的感覺,類似于將derived class地址賦給based clasa對象指針,調用虛函數DisPlay顯示多態性。如果窺視c++編譯器的底層,你會發現,references往往以指針實現出來,因此pass-by-reference通常意味著這真正傳遞的是指針。 ? ? ? 因此如果你有個對象屬于內置類型(如int),pass by reference或pass by reference to const時,選擇pass by value并非沒有道理。這個忠告也適用于STL的迭代器和函數對象,因為習慣上它們都被設計為pass by value。迭代器和函數對象的實踐者有責任看看他們是否高效且不受切割問題的影響。
記住 ①盡量以pass-by-reference-to-const替換pass-by-value.前者通常比較高效,并可避免切割問題(slicingproblem).
②以上規則并不適合與內置類型,以及STL的迭代器和函數對象.對它們而言,pass-by-value往往比較適合.
class Persion { private:std::string m_name;std::string m_addr; };class Student : public Persion { private:std::string m_schoolName;std::string m_schoolAddr; };bool IsValidStudent(Student s) {return true;} 調用 Student s1;bool b_s = IsValidStudent(s1);?? ? ? IsValidStudent函數調用行為如下:編譯器調用student拷貝構造函數拷貝實參到形參,然后形參使用完后再調用析構函數,但該類調用遠不止這些,如student的父類也需要調用拷貝構造函數,而persion中有兩個string成員也需要調用拷貝構造函數,還有student也有兩個string成員需要調用拷貝構造函數,而且這些調用完后還需要調用析構函數。就因為一個pass-by-value操作,而需要花費這么多成本。
pass-by-reference-to-const
將上面的IsValidStudent函數修改如下 bool IsValidStudent(const Student &s) {return true;}這樣沒有調用任何的構造函數和析構函數,形參實際是實參的副本,因此需要加上const保護實參免修改。 對象切割
? ? ? ? 當一個derived class對象以pass-by-value的形式傳遞給一個base-class對象時,base-class會調用拷貝構造函數,且會把derived class的所有行為都切割掉,即編譯器只當成base-class處理。如果用reference和指針,可以防止對象切割。 class Persion { public:Persion(const string &name, const string& addr) : m_name(name), m_addr(addr) {}virtual ~Persion() {} //作為基類,需要定義虛析構函數string GetName() const {return m_name;}string GetAddr() const {return m_addr;}virtual void DisPlay() {cout<<"Person\n";} private:std::string m_name;std::string m_addr; };class Student : public Persion { public:Student(const Persion &persion, const string &sName, const string &sAddr):Persion(persion.GetName(), persion.GetAddr()),m_schoolName(sName),m_schoolAddr(sAddr){}string GetName() const {return m_schoolName;}virtual void DisPlay() {cout<<"Student\n";} private:std::string m_schoolName;std::string m_schoolAddr; };void DisPlayPersion(Persion persion) {std::cout<<persion.GetName()<<endl;persion.DisPlay(); }調用
Persion p("cuancuan", "guangzhou");Student s1(p, "shiyan", "yuexiu");DisPlayPersion(s1);輸出 cuancuan
Person 結果很明顯,沒有調用student的Display函數 修改函數接口參數為pass-by-reference-to-const void DisPlayPersion(const Persion &persion) 同樣調用結果如下 cuancuan
Student
? ? ? ?看到結果,是不是有一種多態性的感覺,類似于將derived class地址賦給based clasa對象指針,調用虛函數DisPlay顯示多態性。如果窺視c++編譯器的底層,你會發現,references往往以指針實現出來,因此pass-by-reference通常意味著這真正傳遞的是指針。 ? ? ? 因此如果你有個對象屬于內置類型(如int),pass by reference或pass by reference to const時,選擇pass by value并非沒有道理。這個忠告也適用于STL的迭代器和函數對象,因為習慣上它們都被設計為pass by value。迭代器和函數對象的實踐者有責任看看他們是否高效且不受切割問題的影響。
記住 ①盡量以pass-by-reference-to-const替換pass-by-value.前者通常比較高效,并可避免切割問題(slicingproblem).
②以上規則并不適合與內置類型,以及STL的迭代器和函數對象.對它們而言,pass-by-value往往比較適合.
總結
以上是生活随笔為你收集整理的条款20:宁以pass-by-reference-to-const替换pass-by-value的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代码中的下划线_是什么意思呢?
- 下一篇: 减肥第一公式