《Effective C++》读后感

s10048587

从八月初在当当上订上这本书,到现在九月初把这本书粗粗读完一遍,期间大概一个月时间,平均每天读一个条款多一点。基本上,每个条款,除了个别的细节外,都能读明白,大致上也都知道“所以然”。但是,如果现在让我合上书,写上一段代码,恐怕这些理解还显得肤浅——毕竟”看“和”写“是两码事,程序员归根结底还是要去”创造“的。

全书55个条款,可以看成55节,分为9章,作者的语言相对平实,思维有些跳跃,而且主要是以“问题”的形式去讲述,有些章节还要再去翻《C++ Primer》这样的书。侯捷的翻译相对还算准确(大致感觉),有些翻译有点拗口,有些也有些不恰当,这里就不记了。

个人最感兴趣的还是关于设计这三章(第4章:设计与声明,第5章:实现,第6章,继承与面向对象设计),这几章浅显易懂,读起来也更流畅,最主要的还是当下手编程时非常实用。作者所提的关于虚函数的声明,关于派生类中函数的重写等等,都与这些内容紧密相关。

模板与泛型编程这一块,以前从来没有接触过,只是知道模板的引入可以大大提高代码的通用性,但是当作者指出C++模板系统可以当作一个图灵机真的让我惊艳了一把。得益于C++的命名系统,模板在编译期的特化过程可以实现出分支与循环(递归)语句,给代码的最终生成带来了很大的灵活性。

当然,印象最深的,还是作者一遍又一遍苦口婆心地强调C++的命名规范和内存管理:前者,C++作为一个强类型语言,加上面向对象特性(类)的加入,使命名规范(包括类型转换)成为一个难以理解更难于驾驭的特性;后者,作为继承自C语言的能够直接操作内存的语言,内存泄漏就像地雷一样让人防不胜防,以至于历来的C++大牛们,花费了大量心血在防范内存分配错误这个问题上,设计出诸如智能指针、operator new甚至Boost程序库中的pool。诚然,对于像Java和C#这样的语言来讲,内存分配只是个概念,虚拟机会自动对程序实行“垃圾回收”,而C和C++这样的手工管理方式虽然带来了极高的运行效率和灵活性,同样也带来了极大的危险性。是的,从这方面来说,C++永远是危险的,而C++程序员就如同在薄冰起舞。

关于C++与其他面向对象语言(如Java)孰优孰少的争论由来已久,网上也时不时有人拿出来炒冷饭,而每次也都沦为双方的口水战,论点也都是一成不变的诸如效率的那些说辞。除去那些意气之争,大家都同意的看法是:对于一个“软件开发人员”来说,Java或者C#就足够了,程序员完全可以把自己的目光集中在软件的外部行为上。论开发效率,两者应该都比C++高,丰富的程序库和设计更为精良的”面向对象体系“(不得不说C++在面向对象特性上表现得还有点原始)使得它们构建起一个方便快捷的生态系统;至于运行效率,对于一个普通的软件来说,完全可以信任Java虚拟机的设计者和硬件性能的提高。但是,对于“系统开发人员”来说,Java之流恐怕就有点力不从心了;另外,对于对效率要求得太高,以至于去逼近硬件发挥出最大潜力的程序,比如不断推动PC硬件更新换代的电脑游戏,比如支撑系统运行的那些底层,比如包括Java虚拟机这样的“中间件“,C或者C++就是必须的了。

我从大二开始自学C++,研一时想重新拾起这个爱好深入学习计算机时,久久想如何选择开发语言。我喜欢C++的”底层“属性,这或许和我的物理专业背景有关,两者都试图从最基本的原理搭建出整个世界。不选择C语言是因为在这个随便编个程序就得几百行的时代,用C写程序太费劲了,缺乏”设计模式“和相对成熟的开发库(Linux下倒是有一整套的开发框架,但是移植性不好)。我是从“界面编程”开始考虑的,如果一门语言或者开发框架连基本的图形界面都难以生成,那就太不“实用”了。一开始想学微软的VC++,从而看上了MFC框架,学了一段时间发现MFC其实是半C半C++的,而且架构相当混乱,网上说连微软都不想支持这东西了,从而动力大减;这本书里讲了一个画图程序的实现例子,可是我跟着书写了一个月,越写越糊涂,写到最后连自己都不知道这些函数为什么要加进去,那些变量为什么声明得那么繁琐,还有哪里来的几十个又长又难懂的宏,从而彻底作罢。

这时我开始关注其他的C++开发框架,偶尔发现了Qt,它架构成熟,使用方便,同时移植性好,不仅能够在Windows和Linux平台上迁移,甚至是嵌入式开发的不二人选。学上一段时间,发现它真的很适合我这样一个没有任何基础的人。现在Qt的学习基本上已经入门,正在啃一些软件开发的框架,有时间会将Qt的学习心得记在这里。

网上列举的C++学习书单,大致看来有这些,读过的只有这本Effective C++和C++ Primer,计划一本本读完。

c  书单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 译者序 前言 第1章 对象的演化 1 1.1 基本概念 1 1.1.1 对象:特性+行为 1 1.1.2 继承:类型关系 1 1.1.3 多态性 2 1.1.4 操作概念:OOP程序像什么 3 1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 复杂性 5 1.3.2 内部原则 6 1.3.3 外部原则 7 1.3.4 对象设计的五个阶段 9 1.3.5 方法承诺什么 10 1.3.6 方法应当提供什么 10 1.4 起草:最小的方法 12 1.4.1 前提 13 1.4.2 高概念 14 1.4.3 论述(treatment) 14 1.4.4 结构化 14 1.4.5 开发 16 1.4.6 重写 17 1.4.7 逻辑 17 1.5 其他方法 17 1.5.1 Booch 18 1.5.2 责任驱动的设计(RDD) 19 1.5.3 对象建模技术(OMT) 19 1.6 为向OOP转变而采取的策略 19 1.6.1 逐步进入OOP 19 1.6.2 管理障碍 20 1.7 小结 21 第2章 数据抽象 22 2.1 声明与定义 22 2.2 一个袖珍C库 23 2.3 放在一起:项目创建工具 29 2.4 什么是非正常 29 2.5 基本对象 30 2.6 什么是对象 34 2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 48 3.4 对象布局 48 3.5 类 48 3.5.1 用存取控制来修改stash 50 3.5.2 用存取控制来修改stack 51 3.6 句柄类(handle classes) 51 3.6.1 可见的实现部分 51 3.6.2 减少重复编译 52 3.7 小结 54 3.8 练习 54 第4章 初始化与清除 55 4.1 用构造函数确保初始化 55 4.2 用析构函数确保清除 56 4.3 清除定义块 58 4.3.1 for循环 59 4.3.2 空间分配 60 4.4 含有构造函数和析构函数的stash 61 4.5 含有构造函数和析构函数的stack 63 4.6 集合初始化 65 4.7 缺省构造函数 67 4.8 小结 68 4.9 练习 68 第5章 函数重载与缺省参数 69 5.1 范围分解 69 5.1.1 用返回值重载 70 5.1.2 安全类型连接 70 5.2 重载的例子 71 5.3 缺省参数 74 5.4 小结 81 5.5 练习 82 第6章 输入输出流介绍 83 6.1 为什么要用输入输出流 83 6.2 解决输入输出流问题 86 6.2.1 预先了解操作符重载 86 6.2.2 插入符与提取符 87 6.2.3 通常用法 88 6.2.4 面向行的输入 90 6.3 文件输入输出流 91 6.4 输入输出流缓冲 93 6.5 在输入输出流中查找 94 6.6 strstreams 96 6.6.1 为用户分配的存储 96 6.6.2 自动存储分配 98 6.7 输出流格式化 100 6.7.1 内部格式化数据 101 6.7.2 例子 102 6.8 格式化操纵算子 106 6.9 建立操纵算子 108 6.10 输入输出流实例 111 6.10.1 代码生成 111 6.10.2 一个简单的数据记录 117 6.11 小结 123 6.12 练习 123 第7章 常量 124 7.1 值替代 124 7.1.1 头文件里的const 124 7.1.2 const的安全性 125 7.1.3 集合 126 7.1.4 与C语言的区别 126 7.2 指针 127 7.2.1 指向const的指针 127 7.2.2 const指针 127 7.2.3 赋值和类型检查 128 7.3 函数参数和返回值 128 7.3.1 传递const值 128 7.3.2 返回const值 129 7.3.3 传递和返回地址 131 7.4 类 133 7.4.1 类里的const和enum 133 7.4.2 编译期间类里的常量 134 7.4.3 const对象和成员函数 136 7.4.4 只读存储能力 139 7.5 可变的(volatile) 140 7.6 小结 141 7.7 练习 141 第8章 内联函数 142 8.1 预处理器的缺陷 142 8.2 内联函数 144 8.2.1 类内部的内联函数 145 8.2.2 存取函数 146 8.3 内联函数和编译器 150 8.3.1 局限性 150 8.3.2 赋值顺序 150 8.3.3 在构造函数和析构函数里隐藏行为 151 8.4 减少混乱 152 8.5 预处理器的特点 153 8.6 改进的错误检查 154 8.7 小结 155 8.8 练习 155 第9章 命名控制 157 9.1 来自C语言中的静态成员 157 9.1.1 函数内部的静态变量 157 9.1.2 控制连接 160 9.1.3 其他的存储类型指定符 161 9.2 名字空间 161 9.2.1 产生一个名字空间 162 9.2.2 使用名字空间 163 9.3 C++中的静态成员 166 9.3.1 定义静态数据成员的存储 166 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 10.2.1 函数中的引用 177 10.2.2 参数传递准则 178 10.3 拷贝构造函数 179 10.3.1 传值方式传递和返回 179 10.3.2 拷贝构造函数 182 10.3.3 缺省拷贝构造函数 187 10.3.4 拷贝构造函数方法的选择 188 10.4 指向成员的指针

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值