More Effective C++ 第六部分 杂项讨论
Posted zhangqixiang5449
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了More Effective C++ 第六部分 杂项讨论相关的知识,希望对你有一定的参考价值。
32.在未来时态下发展程序
软件最初的开发与后续开发和维护的人通常不是同一批,所有我们需要强制某些规范,例如利用c++语言特性强制对象产生与heap内。不要想着我记得不去做某些事就行,需要强制实行。
确保operator和函数拥有自然的语意。应和内建类型一样,如果疑惑,不妨看看ints有怎样的表现。
任何事情之一有人能做,就会有人做。例如抛出异常,将对象自我赋值,在为获得初值前使用对象,给函数非法的值……
尽量避免使用RTTI作为设计基础的层层的if else语句。
提供完备的类,即使某些部分现在还没有被使用。如果有了新的需求,你不用回过头去改它们。
将你的接口设计得便于常见操作并防止常见错误。使得类容易正确使用而不易用错。例如,阻止拷贝构造和赋值操作,如果它们对这个类没有意义的话。防止部分赋值。
尽量使你的代码泛化,除非有巨大的不良后果。例如,如果在写树的遍历算法,考虑将它通用得可以处理任何有向不循环图。 未来时态的考虑增加了你的代码的可重用性、可维护性、健壮性,已及在环境发生改变时易于修改。它必须与进行时态的约束条件进行取舍。
33.将非尾端类设计为抽象类
在原有具体类被当做基类使用时,需要到导入一个新的抽象类。
其中C1是一个具体类,是可以当做正常的对象被构造出来并有意义的,A是一个抽象类,其含有C1,C2的共同特性。
若不采用这种方法导致的问题的一个例子:
class Animal
public:
Animal& operator=(const Animal& rhs);
...
;
class Lizard: public Animal
public:
Lizard& operator=(const Lizard& rhs);
...
;
class Chicken: public Animal
public:
Chicken& operator=(const Chicken& rhs);
...
;
下面这样的代码将会出现问题
Lizard liz1,liz2;
Animal* pAnimal1 = &liz1;
Animal* pAnimal2 = &liz2;
*pAnimal1 = *pAnimal2;
//将会调用Animal的operator=,导致liz1和liz2的base class部分相同,
//但derived class部分还是原来的
一个解决办法是让operator=成为虚函数,接受一个Animal&类型参数,返回对应的类型。(C++要求虚函数原型相同,尽管允许函数返回引用时可以返回派生类引用,但函数参数仍然必须完全相同.)例如
class Lizard: public Animal
public:
virtual Lizard& operator=(const Animal& rhs);
...
;
但是这样将导致将一只鸡赋值给一只蜥蜴是“正确”的,因为其接受对象的类型是Animal&。
解决这个问题的方式使用dynamic_cast但会导致性能和异常问题;
class Lizard: public Animal
public:
virtual Lizard& operator=(const Animal& rhs);
Lizard& operator=(const Lizard& rhs); //同类型的不需要dynamic_cast
...
;
Lizard& Lizard::operator=(const Animal& rhs)
return operator=(dynamic_cast<const Lizard&>(rhs));
我们不能阻止Animal对象间的赋值,因为其位具体类,是可以赋值的。
终极解决方案是:
采用这种策略直接禁止了像*pAbstractAnimal1=*pAbstractAnimal2的操作,而仍然像*pAnimal1=*pAnimal2的操作并且在编译时检查类型.
然而有时候需要使用第三方库,并继承其中一个具体类,由于无法修改该库,也就无法将该具体类转为抽象基类,这是就需要采取其他选择:
1). 继承自现有的具体类,但要注意上边的assignment问题,并小心条款3所提出的数组陷阱.
2). 试着在继承体系中找一个更高层的抽象类,然后继承它.
3). 以”所希望继承的那么程序库类”来实现新类.例如使用复合或private继承并提供相应接口.此策略不具灵活性.
4). 为”所希望继承的那么程序库类”定义一些non-member,不再定义新类.
34.如何在同一程序中结合C++和C
压抑name mangling
c++的函数经过name mangling产生独一无二的名称,而c并不会经过name mangling,因为c不支持重载。所以在C++程序中调用c程序需要压抑name mangling。方法如下:
extern "C" //使用extern "C" 压抑
void drawLine();//C函数
extern "C"
//一些C函数
当某些头文件由C和C++共有可以这样写
#ifdef _cplusplus
extern "c"
#endif
//函数声明
#ifdef _cplusplus
#endif
static的初始化
static对象在main开始前构造,在mian结束后析构,与C冲突。为解决这一问题每个编译器厂商都会提供某种语言以外的机制启动static对象的构造和析构,具体方法需要查看编译器文档。
动态内存分配
C++使用new和delete,C使用malloc和free,需要一一对应,不能用new分配内存用free释放。
数据结构的兼容性
C和C++之间对数据结构做双向交流应该是安全的。因为Structor是兼容的,除非其中包含虚函数。
35.让自己习惯与标准C++语言
……
以上是关于More Effective C++ 第六部分 杂项讨论的主要内容,如果未能解决你的问题,请参考以下文章