5 其他杂项
~~~~~~~~~~~
5.1 在未来时态下开发程序
=========================
1. 用C++语言自己来表达设计上的约束条件,而不是用注释或文档
2. 未来时态的考虑不是问一个类现在正被怎么使用,而是问这个类是被设计为怎么去使用的.
3. 未来时态的考虑只是简单地增加了一些额外约束:
* 提供完备的类,即使某些部分现在还没有被使用。如果有了新的需求,你不用回过头去改它们。
* 将你的接口设计得便于常见操作并防止常见错误。使得类容易正确使用而不易用错。
例如,阻止拷贝构造和赋值操作,如果它们对这个类没有意义的话。防止部分赋值。
* 如果没有限制你不能通用化你的代码,那么通用化它。
例如,如果在写树的遍历算法,考虑将它通用得可以处理任何有向不循环图。
5.2 将非尾端类设计为抽象类
===========================
1. 绝大部分纯虚函数都没有实现,但纯析构函数是个特例.它们必须被实现,因为它们在派生类析构函数被调用时也将被调用.
2. 如果有两个实体类C1和C2,并且C2公有继承C1,那么你应该将两个类的继承层次改为三个类的继承层次,通过创造一个新的抽象类A,并将C1和C2都从它继承.
这种修改的重要价值是强迫你确定抽象类.
其目的是,确认有用的抽象,并强迫它们放入抽象类这样的实体.
注意,只有在设计出得类能被将来的类从它继承而不需要它做任何修改时,你才能从抽象类中获得好处.
5.3 如何在同一程序中混合使用C++和C
===================================
1. 确保C++编译器和C编译器兼容
5.3.1 名变换
-------------
1. 名变换,就是C++编译器给程序的每个函数换一个独一无二的名字。在C中,这个过程是不需要的,因为没有函数重载,但几乎所有C++程序都有函数重名.因此C++编译器通常会对函数进行名变换.这需要一个办法来告诉C++编译器不要在这个函数上进行名变换.
2. 要禁止名变换,需要使用C++的extern "C"指示符.
不要将extern 'C'看作是申明这个函数是用C语言写的,应该看作是申明在个函数应该被当作好象C写的一样而进行调用。
- extern "C" void simulate(int iterations);
- extern "C"{
- void drawLine(int x1, int y1, int x2, int y2);
- void twiddleBits(unsigned char bits);
- void simulate(int iterations)
- }
5.3.2 静态初始化
-----------------
1. 在C++的main执行前和执行后都有大量代码被执行。
静态的类对象和定义在全局的、命名空间中的或文件体中的类对象的构造函数通常在main被执行前就被调用。
通过静态初始化产生的对象也要在静态析构过程中调用其析构函数;这个过程通常发生在main结束运行之后。
2. 如果main()不是用C++写的,那么前后的代码可能就不会被执行,从而C++库中的静态对象可能没有被初始化和析构.
最好的办法是将C的main()改名,然后在C++的main()中调用C的main()函数
5.3.3 动态内存分配
-------------------
1. 将C++的new和delete与malloc和free进行严格的分离
5.3.4 数据结构的兼容性
-----------------------
1. 两种语言间的函数可以安全地交换指向对象的指针和指向非成员的函数或静态成员函数的指针
2. C++中非虚函数的的struct或class的对象兼容了它们在C中的孪生版本(其定义只是去掉了这些成员函数的声明)
在C++的struct中增加虚函数,会使得对象使用一个不同的内存结构,这就跟C不兼容了.
从其它结构(或类)进行继承的结构,通常也改变其内存结构,所以有基类的结构也不能与C函数交互。