第一篇 动机
讲述C++什麽地方吸引了作者,和作者为什麽要在编程中使用C++。
一开始,作者就提出了C++本质——抽象和封装:类。 抽象可以帮助设计者可以有所侧重,C++使我们更容易把程序看作抽象的集合,同时也隐藏了那些用户无须关心的抽象工作细节。封装则是C++可以把问题精心划分为分割良好的模块,使得模块与模块之间的信息得到很好的隐藏。模块化不完全同于C中也能实现模块化的函数,书中Page4上小题“不用类来实现”中已经阐述了这个观点——C中函数模块化也是有效的,但是与C++类有3个明显的缺点:①C中函数不是内联的,因此即使当跟踪关闭的时候,它还能保持函数调用的开销(“效率”是使C++经久不衰的最主要原因之一);②C中函数引入了很多全局函数名,而C++引入一个类名即可;③C++类可以使该类具有一般性,C++中有重载和覆盖,C中则必须为每种情况都提供一个函数(C不支持重载,所以参数不同导致)。C++使问题模块化,然后会给代码复用、软件开发和维护等带来很大便利。
作者在解释“为什麽用C++工作” 中,提到了编程语言的规范(L注:这一点我一直很看重,因为在软件开发的过程中,大部分时候是和同事一起完成,按照已有的编程语言规范可以使你工作很愉快,可以帮助你把精力大部分放在软件的算法和架构上去),其中说道很多后来的编程语言中使用的内存管理——垃圾回收机制,但垃圾回收要求系统在运行速度、编译器、运行时系统复杂度等方面付出代价。但C++采用构造函数和析构函数解决内存使用问题,不过这给程序员了一定压力。说实话,我觉得垃圾回收机制就是对析构函数的进一步封装(仅是个人理解),但是这要求程序设计者对程序整个运行状况都必须了解,即就是所谓的“庖丁解牛”!
另外,文中例举到①成功使用动态内存的必须操作:知道要分配多大的内存;不使用超出分配的内存范围外的内存;不再需要时释放内存;只有不再使用时,才释放内存;只释放分配的内存;切记检查每个分配请求,以确保成功。 ②编程环境:你把自己的程序交给编译器编译,编译器把相应的机器代码放入一个文件,连接程序读取这个文件,把这些机器指令和相关库中的机器指令结合起来,放入另一个文件,得到执行这个文件的命令后,操作系统把文件读入内存,并且跳到文件的第一条指令。
第二篇 类和继承
这一篇没怎么看懂,对于我来说很抽象!我还是记录一下几个知识点:代理类、句柄、虚函数、SmartPointer(智能指针)、CopyOnWrite(写时复制)、(纯)虚函数。第十一章(什麽时候不应当使用虚函数)我觉得有意思,因为对象在调用虚函数的时候容易混淆,毕竟C++的多态就是靠这个。虚函数的详细解释参考:C++虚函数表解析(转) 和 虚继承与虚函数表,下面给出书中一个例子:
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Base
{
public:
void f();
virtual void g();
};
class Derived: public Base
{
public:
void f();
virtual void g();
};
Base b;
Derived d;
Base * bp = &b;
Base * bq = &d;
Derived * dp = &d;
bp->f(); /*Base::f()*/ bp->g(); /*Base::g()*/
bq->f(); /*Base::f()*/ bq->g(); /*Derived::g()*/
dp->g(); /*Derived::g()*/ dp->f(); /*Derived::f()*/
你会发现只有指针的静态类型与它所指向的实际对象的类型不同时,非虚函数f和虚函数g运行起来才会有所差别。另外书中一个例子:
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
Base* bp;
Derived* dp;
bp = new Derived;
dp = new Derived;
delete bp; // Base必须有一个虚析构函数
delete dp; // 这里虚析构函数可要可不要
这里一个基类指针来删除一个派生类对象,Base必须有一个虚析构函数。这里我是这样子理解的,派生类Derived继承自基类Base,由于Base没有析构函数(不考虑默认的),所以Derived也不会有(因为自己也没添加),应该想到基类和派生类构造函数和析构函数执行顺序:基类构造函数→派生类构造函数→派生类析构函数→基类析构函数。上例中派生类没有析构函数,所以按照上诉执行过程,最后基类必须要有析构函数,否则对象资源不能很好的释放。
第三篇 模版
感觉这一张就是介绍STL的!!!幸好之前对STL有一点的了解,要不然这一篇也是看不懂的。
里面提到一个之前没有注意的知识点:在使用数组的时候,下标和指针均可以访问数组,但是这两者的区别? 最简单的答案:下标容易理解,而指针效率更高。更深层次的回答:在下标中,下标值本身就有意义,而与它是否用于下标无关;在指针中,要访问容器的元素没有必要知道容器的标识(因为指针就包含了所有必要的信息) 。简单地说,就是程序只要拥有一个指向数组元素的指针就可以访问整个数组,而通过下标进行元素访问的程序就要另外知道正在使用的是哪一个数组。不过需要注意:“几个数组的对应元素”的概念在使用下标实现的时候远比使用指针更简单,释放数组时(可结合数组的声明周期到了???),会不通知指针的所有者,一次性使所有指向数组元素的指针失效,而下标则仍然保有其意义。
在P145中注释中提高一个:内建数组既不能被复制也不能赋值。 你可以将内建数组传递给一个函数,不过这不是数组复制,而是将该数组转化成一个指向数组元素首地址的指针,然后将这个指针传递给函数。这点可以认真思考思考!
指针和整数相减或相加都会得到一个新的指针。
在第十六章“作为接口的模版” 举的一个例子,然后以此改进,这个过程值得学习。
第十八章里提到“反转链表” ,作者列出了具体代码(那种方法是我之前没有遇见的)。
第二十章“函数对象” 也是不错,不能动态的创建函数,不过我觉得没在这个必要吧。
第四篇 库
这一篇看着头疼!!!
内建类型和内置类型有什麽联系和区别?