Prefer pass-by-reference-to-const to pass-by-value
        这个问题在在C++是非常常见的。传值和传引用巨大的差别在于你所使用的参数是其本身还是其副本。缺省情况下C++是以by value 传递的。其副本是对象本身的copy 构造函数自动调用的。有关对象自动调用的五个函数请看条款12.下面看一下例子吧    :
// refer_value.cpp : 定义控制台应用程序的入口点。
//2011/10/5 by wallwind at sunrise
#include "stdafx.h"
#include <iostream>
using namespace std;
class Base
{
public:Base(){cout<<"Base()"<<endl;}~Base(){cout<<"~Base()"<<endl;}
private:string str1;string str2;
};
class Derived:public Base
{
public:Derived(){cout<<"Derived()"<<endl;}~Derived(){cout<<"~Derived()"<<endl;}bool retTrue(){return true;}
private:string str1;string str2;
};
bool validateDerived(Derived d)
{return d.retTrue();
}
int _tmain(int argc, _TCHAR* argv[])
{Derived d;bool bb=validateDerived(d);system("pause");return 0;
}
运行结果如图:
从结果我们可以看到 构造函数,析构函数都调用了,其实远不止这些,因为上述两个类都含有两个string,他们也相应的调用构造函数,就是说四次string构造动作,还有析构。
总计12次,也就是我们简单的一个调用,动用了这么多函数。很浪费资源。
下面我们用 pass-by-reference-to-const来。
修改代码为
bool retTrue() const{return true;} bool validateDerived(const Derived& d)
{return d.retTrue();
}

运行的结果:

如图,程序只调用了构造函数。在这里注明书中说没有调用任何构造函数和析构函数,应该是调用了构造函数了吧。跪求高人解释
by-reference避免了对象切割,什么是对象切割,请看下边的例子。
// refer_value.cpp : 定义控制台应用程序的入口点。
//2011/10/5 by wallwind at sunrise
#include "stdafx.h"
#include <iostream>
using namespace std;
class Window
{
public :Window(){};void name()const;virtual void display()const;
};
void Window::name()const
{cout<<"window name"<<endl;
}
void Window::display()const
{cout<<" window display()"<<endl;
}
class WindowWithScrollBars:public Window{public:WindowWithScrollBars(){};virtual void display() const;
};
void WindowWithScrollBars::display() const
{cout<<"WindowWithScrollBars display()"<<endl;
}
void pintNaandWind(Window w)
{w.name();w.display();
}
int _tmain(int argc, _TCHAR* argv[])
{WindowWithScrollBars wwsb;pintNaandWind(wwsb);return 0;
}

运行的结果如图所示:

 
 
可以看出,我们想得到WindowWithScrollBars display() ,但是我们得到的是上述的。它调用 是window对象,而不是子类的。因为他是by value,WindowWithScrollBars的所有特化信息都会被切除,这就是对象切割。那么解决办法就是 pass-by-reference-to-const,
修改代码如下:

void pintNaandWind(const Window& w){w.name();w.display();
} 

运行结果得到:
 
从中我们看到了通过pass-by-reference-to-const,得到了我们想要的结果。

解释一下:
(1)所谓的slicing问题,也就是如果你把子类的对象赋值给父类的对象,如果用reference和指针,当然是可以的,而且这也是virtual的实现必需品。但是,如果用pass-by-value,就会出现,传进去的总是父类的对象,在传递对象的时候出现了切割问题。

(2)如果窥视c++编译器的底层,你会发现,references往往以指针实现出来,因此pass-by-reference通常意味着这真正传递的是指针。因此如果你有个对象属于内置类型(如int),pass by reference或pass by reference to const时,选择pass by value并非没有道理。这个忠告也适用于STL的迭代器和函数对象,因为习惯上它们都被设计为pass by value。迭代器和函数对象的实践者有责任看看他们是否高效且不受切割问题的影响。

(3)内置类型都相当的小。因此有人认为,所有小类型的types都是pass by value的合格候选人,甚至他们是用户自定义的class亦然。这是个不可靠的推论。对象小并不就意味其copy构造函数不昂贵。许多对象,包括STL容器,内含的东西只比一个指针多一些,但复制这种东西对象却需要承担“复制那些指针的每一样东西”。那将非常昂贵。

即使小型对象拥有并不昂贵的copy构造函数,还是可能有效率上的争议。某些编译器对待“内置类型”和“用户自定义类型”的态度截然不同,总是两者有相同的底层表述。举个例子,某些编译器拒绝把只由一个double组成的对象放进缓存器内,却很乐意在一个正规基础上对光秃秃的double那么做。当这种事发生,你更应该以by reference方式传递此等对象,因为编译器当然会将指针(references的实现体)放进缓存器内,绝无问题。

小型的用户自定义类型并不必然成为pass by value优良候选人的另一个理由是,作为一个用户自定义类型,其大小容易有所改变。甚至当你改用另一个c++编译器都有可能改变type的大小。举个例子,某些标准程序库实现版本中的string类型比其他版本大七倍!

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

Effective c++学习笔记条款20:宁以 pass-by-reference-to-const替换pass-by-value相关推荐

  1. Effective C++条款20解读:宁以pass by reference to const替换pass by value

    我们先来看一个简单的程序: #include <iostream> using namespace std;class A { private:string name;string add ...

  2. Effective C++ 学习笔记 条款05 了解C++默默编写并调用了哪些函数

    当写下一个空类时,编译器会为你合成一个拷贝构造函数.一个拷贝赋值运算符.一个析构函数,如没有声明其他的构造函数,编译器会合成一个默认构造函数.这些都是inline的public成员. 当类有一个引用成 ...

  3. Effective C++ 学习笔记 第七章:模板与泛型编程

    第一章见 Effective C++ 学习笔记 第一章:让自己习惯 C++ 第二章见 Effective C++ 学习笔记 第二章:构造.析构.赋值运算 第三章见 Effective C++ 学习笔记 ...

  4. 深度学习笔记(20) 端到端学习

    深度学习笔记(20) 端到端学习 1. 端到端的深度学习概念 2. 语音识别的端到端学习 3. 人脸识别的端到端学习 4. 机器翻译的端到端学习 5. 非端到端 6. 端到端的优缺点 7. 端到端的关 ...

  5. 《游戏设计艺术(第2版)》——学习笔记(20)第20章 世界中的角色

    <游戏设计艺术(第2版)>学习笔记(20) 第20章 世界中的角色 游戏角色的本质 小说角色 电影角色 游戏角色 化身 理想型 白板 创造令人信服的游戏角色 角色窍门1:列出角色的功能 角 ...

  6. 【Effection C++】读书笔记 条款20~条款23

    [Effective C++]Part4 设计与声明 条款20:宁以pass-by-reference-to-const替换pass-by-value 尽量以pass-by-reference-to- ...

  7. 【Effective C++ 学习笔记】

    条款02:尽量以const,enum,inline替换 #define #define定义的常量也许从未被编译器看见,也许在编译器开始处理源码之前它就被预处理器移走了: #define不重视作用域,不 ...

  8. Java:Effective java学习笔记之 考虑实现Comparable 接口

    Java 考虑实现Comparable 接口 考虑实现Comparable 接口 1.Comparable接口 2.为什么要考虑实现Comparable接口 3.compareTo 方法的通用约定 4 ...

  9. 《童虎学习笔记》20分钟实战ProxySQL MGR高可用及读写分离架构

    本文章配套视频 https://www.ixigua.com/7086085500540289572?id=7087546160079962660 本专栏全部文章 https://blog.csdn. ...

最新文章

  1. 这些重大科技领域问题,听听专家怎么说
  2. linux普通用户home目录锁定
  3. 双赛道近四百万奖金,2021全国人工智能大赛来了!
  4. bzoj4563放棋子
  5. jzoj3832-在哪里建酿酒厂【指针】
  6. hdfs中Exception in createBlockOutputStream以及MapReduce中I/O error constructing remote block reader
  7. 根据控制点坐标对完成坐标转换
  8. 基于队列的二叉树层次遍历
  9. Mac 版pr 破解教程,亲测可行。
  10. 麦吉尔大学计算机科学申请,三大权威榜单为你诠释:加拿大计算机科学哪家强?...
  11. linux安装vsftpd
  12. 【C语言初阶】求最小公倍数的三种方法
  13. supervisor+nginx+cesi
  14. CTF新生赛之Writeup
  15. 记一次小米路由器任意文件读取漏洞
  16. 计算机防火墙无法关闭,为什么我电脑的防火墙关不了(win7电脑防火墙怎么关)
  17. web前端面试题附答案035-关于number考点大全,走过路过不会错过
  18. 使用ant design的table控件最后一列固定(fixed)遇到的问题
  19. 按文件夹名匹配并复制文件夹及子文件
  20. 计算机主板用塑料做的好吗,旧电脑零件千万别扔 重新利用竟还能做出这么多新设备...

热门文章

  1. python编写三角形_如何让代码编写python三角形?
  2. starGAN复现及遇到问题
  3. AB分区保留面具升级系统(安卓11不丢面具升级系统)
  4. python 检查身份证号的正确性
  5. Cadence从原理图到PCB的具体步骤
  6. 编写Python爬虫爬取豆瓣出版社列表并写入文件
  7. 群体领袖简介(25)
  8. Vpython界面的设置
  9. 用pycharm写python_在PyCharm中使用VPython
  10. 猿辅导的python课_猿辅导和一课哪个更好?