条款20:以const-reference传递替换by-value传递

缺省情况下,C++中函数参数的传递方式为by-value。即函数都是以实际参数的副本进行传递,而函数返回的也是一个副本。考虑如下实例程序:

 1 #include <iostream>
 2
 3 class Person
 4 {
 5 public:
 6     Person(){ cout << "Person的构造函数" << endl; }
 7     virtual ~Person(){ cout << "Person的析构函数" << endl; }
 8     Person(const Person& p){ cout << "Person的copy构造函数" << endl; }
 9
10 private:
11     string name;
12     string address;
13 };
14
15 class Student : public Person
16 {
17 public:
18     Student(){ cout << "Student的构造函数" << endl; }
19     ~Student(){ cout << "Student的析构函数" << endl; }
20     Student(const Student& p){ cout << "Student的copy构造函数" << endl; }
21     void setID(string id){ studentID = id; }
22     string getID() const{ return studentID; }
23
24 private:
25     string studentID;
26 };
27 bool validateStudent(Student s)
28 {
29     return s.getID().length() != 0 ? true : false;
30 }
31
32
33 int main()
34 {
35     Student s;
36     s.setID("123456");
37     bool isOK = validateStudent(s);
38     std::cout << "validateStudent(): " << isOK << std::endl;
39 }


现在分析一下上述函数执行流程:执行validateStudent(s)传入参数是先调用一次copy构造函数构造一个s的副本,从该函数退出时,再调用一次析构函数销毁s的副本。此外,Student中有一个string变量,需要调用一次string的构造函数,Student继承自Person,因此需要调用一次Person构造函数,而Person中又有两个string,再调用两次string的构造函数,因此总共需要构造5次,与之对应的需要析构5,这就是by-value传递的代价。

那么我们如何才能不构造就进行参数传递呢?当然是const-reference了,如下:

Bool validateStudent(const Student& s);

这种参数传递方式不涉及任何的构造与析构调用。

同时通过by-value方式传递参数也可以造成对象被截断(slicing)的问题,如下所示:

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Window
 6 {
 7 public:
 8     string name() const{ return "Window"; };            // 返回窗口名
 9     virtual void display(){ cout << "Display Window" << endl; };         // 显示窗口
10 };
11
12 class EXWindow : public Window
13 {
14 public:
15     virtual void display(){ cout << "Display EXWindow" << endl; };
16 };
17
18 void printNameAndDisplay(Window w)
19 {
20     cout << "窗口名:" << w.name() << endl;
21     w.display();
22 }
23
24 int main()
25 {
26     EXWindow exw;
27     printNameAndDisplay(exw);
28
29     return 0;
30 }


怎么会出现这种情况呢?display()可是虚函数啊,它不应该执行多态调用吗?原来是参数传递出现问题了。值传递中,无论传入的是什么类型,其构造副本的时候只是按照形参的类型来构造,也就是说传入的副本是个Window类型的,这种现象被称为截断。

如果改为以引用传递会如何呢?

1 void printNameAndDisplay(const Window& w)
2 {
3     cout << "窗口名:" << w.name() << endl;
4     w.display();
5 }


我们必须知道引用的本质就是用指针实现的。因此传入到是当前对象本身而不是副本,因此会发生多态调用了。

注意:

我们如上讨论的主要问题就是by-value传递会执行很多的构造与析构过程,而by-reference传递会很好地解决这个问题。但是并不是所有类型的变量都适合by-reference传递。比如内置类型、STL迭代器、函数对象,对它们而言,by-value传递往往比较合适,并且效率高些。

时间: 2024-07-29 01:36:24

条款20:以const-reference传递替换by-value传递的相关文章

Effective C++:条款20:宁以 pass-by-reference-to-const替换pass-by-value

(一) 调用函数的时候如果传递参数pass-by-value,那么函数参数都是以实际实参的副本为初值,调用端所获得的亦是函数返回值的一个复件. 看下面代码: class Person { public: Person(); virtual ~Person(); private: string name; string address; }; class Student : public Person { public: Student(); ~Student(); private: string

条款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_sch

&lt;&lt;Effective c++&gt;&gt;读书笔记---条款20:宁以pass-by-reference-to-const替换pass-by-value

尽量以pass-by-reference-to-const替换pass-by-value.前者通常比较高效,因为它可以避免调用拷贝构造函数和析构函数,并且可以避免切割问题.一下是一个很好的切片问题实例: class A { public: A() {} virtual ~A() {} virtual void Display() { cout << "A::Display()" << endl; } }; class B : public A { public:

《Effective C++》——条款20:宁以pass-by-reference-to-const替换pass-by-value

切割(slicing)问题 请看下面代码: class Window { public: ... std::string name()const; //返回窗口名称 virtual void display()const; //显示窗口和其内容 }; class WindowWithScrollBars:public Window { public: ... virtual void display()const; }; 现在假设你希望写个函数打印窗口名称,然后显示该窗口,代码如下所示: voi

effective c++ 条款20:宁以pass-by-reference-to-const替换pass-by-value

记住: 尽量以pass-by-reference-to-const替换pass-by-value.前者通常比较高效,并可避免切割问题(slicing problem). 以上规则并不适用于内置类型,以及STL的迭代器和函数对象.对它们而言,pass-by-value往往比较适当. class Person { public: Person(); virtual ~Person(); ... private: string name; string address; }; class Studen

条款20:宁以pass-by-reference-to-const替换pass-by-value(Prefer pass-by-reference-to-const to pass-by-value)

NOTE: 1.尽量以pass-by-reference-to-const 替换pass-by-value.前者通常比较高效,并可避免切割问题(slicing problem). 2.以上规则并不适用于内置类型,以及STL的迭代器和函数对象.对他们而言,pass-by-value往往比较合适.

Effective C++条款20:宁以pass-by-reference-to-const替换pass-by-value。Test code

看了第20条感觉以前没有注意那么多,尤其是在程序运行的效率方面没有很注意,所以就做了个测试: test.h文件 #include <iostream> //using namespace std; class Person{ public: Person(); virtual ~Person(); private: std::string name; std::string address; }; class Student:Person{ public: Student(); ~Studen

《Effective C++》条款20宁以pass-by-reference-to-const替换pass-by-value

<Effective C++> 条款20:宁以pass-by-reference-to-const替换pass-by-value 缺省情况下C++以by value方式传递对象至函数.除非你另外知道,否则函数参数都是以实际参数的副本为初值,而调用端所获得的亦是函数返回值的一个复件.这些复件系由copy构造函数产出,这可能使得pass-by-value成为昂贵的费时的操作. 通过pass-by-reference-to-const的传递方式效率高的多:原因是没有任何构造函数或析构函数被调用,因为

effective C++ 读书笔记 条款20

条款20:宁以 pass-by-reference-to-const 替换 pass -by -value 1:采用后者效率高:看代码: #include <iostream> using namespace std; class Person { public: Person() { cout<<"Person()"<<endl; } Person(const Person& p) { cout<<"Person(co