Effective C++ --1让自己习惯C++
Effective C++ --2构造/析构/赋值运算
Effective C++ --3资源管理
Effective C++ --4设计与声明
Effective C++ --5实现
Effective C++ -- 6继承与面向对象设计
EffectiveC++ --7模板与泛型编程
Effective C++ --8 定制new和delete && 9杂谈讨论
下面整理的书中遇到的零碎知识点:
1、符号表
在条款02中提到,参考http://bbs。csdn。net/topics/330129162
英语为symbol table, 翻译成"符号表"应该好理解一些,针对计算机语言,在不同的地方,它的用处也不一样。有词法分析时分词用的符号表。用来把所有用到的标识符区分出来。也有做语法分析时用的语法元素的符号表。编译成目标文件时,也会产生用于内/外部符号定位/链接用的符号表。生成可执行文件时也有类似的符号表。不论在什么地方,符号表的基本都可以看成一个名称索引表,为了方便数据归类查找用的。
#define不会讲宏放入记号表,这是为何?
symbol table是动态的。
比如你写int a = 10,那分词后会得到 int, a, =, 10, ; 这五个符号。这时,分词用的符号表里就只有这几个符号及与之对应的信息(比如类型,行号,偏移,文件之类的)。在做语法分析的时候,会直接使用分词的结果。一般就是分词用的符号表中的编号。当需要更多的符号信息的时候,就会从分词符号表时查。
而像宏之类的东西,在编译之前,会进行预处理。它所用的符号在预处理时就处理过了,所以在具体的编译时,是没有这些信息的。
实际上,预处理本身也是一次"编译"的过程。在预处理的过程中也会有它自己的"符号表"。
2、the enum hack
在条款02中提到,当编译器不允许static整数型class常量完成in class初值设定时使用的策略,理论基础是“一个属于枚举类型的数值可权充ints被使用”。
classd GamePlayer{ private: enum{ NumTurns = 5 }; intscores[NumTurns]; };
3、mutable
在条款03中提到。
mutable的中文意思是:“可变的、易变的”与constant(即C++中 const)是反义词。C++中的mutable是为了突破const限制而设置的,被mutable修饰的变量将永远处于可变状态,即使是位于const修饰的函数中。mutable又是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。
4、常量性转除
在条款03中提到,这里利用此技术来实现由non-const成员函数转换为调用const函数来避免代码重复。用到了两个转型,一个转型用static_cast来把non-const对象转型为const对象,调用const成员函数,第二个把const成员函数返回值const类型转换为non-const类型。
const char& operator[](std::size_tposition) const{ //const成员函数 returntext[position]; } char& operator[](std::size_tposition){ //non-const成员函数 returnconst_cast<char&>( //将返回值的const移出 static_cast<constTextBlock&>(*this) //为*this加上const [position] //调用const成员函数 ); }
5、堆和栈
一般动态分配空间在堆,局部变量在栈。
堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码 中的delete语句才能正确的释放本内存空间。我们常说的内存泄露,最常见的就是堆泄露(还有资源泄露),它是指程序在运行中出现泄露,如果程序被关闭掉的话,操作系统会帮助释放泄露的内存。
栈:在函数调用时第一个进栈的主函数中的下一条指令(函数调用语句的下一条可执行语句)的地址然后是函数 的各个参数,在大多数的C编译器中,参数是由右往左入栈,然后是函数中的局部变量。
6、编译单元
产出单一目标文件的源码。当一个c或cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有必要信息的单个源文件,这个源文件就是一个编译单元。这个编译单元会被编译成为一个与cpp文件名同名的目标文件(.o或是.obj)。连接程序把不同编译单元中产生的符号联系起来,构成一个可执行程序。
7、vptr(virtual table pointer)
在条款07中提到。欲实现virtual函数,对象必须携带某些信息,主要用来在运行时决定哪一个virtual函数该被调用。Vptr指向一个由函数指针构成的数组,称为vtbl(virtual table)。每一个带有virtual函数的类都有一个相应的vtbl。当对象调用某个virtual函数时,实际被调用的函数取决于该对象的vptr所指的那个vtbl—编译器在其中寻找适当的函数指针。
8、TR1
在条款13中提到,在条款54中仔细介绍。
C++ TechnicalReport 1 (TR1)是ISO/IEC TR 19768, C++ Library Extensions(函式库扩充)的一般名称。TR1是一份文件,内容提出了对C++标准函式库的追加项目。这些追加项目包括了正则表达式、智能指针、哈希表、随机数生成器等。TR1自己并非标准,他是一份草稿文件。然而他所提出的项目很有可能成为下次的官方标准。这份文件的目标在于「为扩充的C++标准函式库建立更为广泛的现成实作品」。
C++ tr1是针对C++标准库的第一次扩展。即将到来的下一个版本的C++标准c++0x会包括它,以及一些语言本身的扩充。tr1包括大家期待已久的smart pointer,正则表达式以及其他一些支持范型编程的东东。草案阶段,新增的类和模板的名字空间是std::tr1。
9、80-20经验法则
平均而言一个程序往往将80%的执行时间花费在20%的代码上。
这一法则提醒我们,要找出这可以有效增加程序整体效率的20%代码,然后将它inline或竭尽所能地将它瘦身。
10、“mixin”风格的基类
在条款49中提到。
mixin风格的bases class,用以支持class专属的set_new_handler。如何针对某个类别计数?通常的做法是:针对该类别设计一组static成员和函数。使用“mixin”风格的基类,可以解决多个类需要多个static成员和函数的问题。此类专为管理类型信息,或者说专为管理static而存在,建立一个同一的包含static的基类,需要的类继承此类。
“mixin”风格之基类应具有如下特征:
(1)是个模板类
(2)模板参数不被使用(此参数只为生成相应类别之static)
(3)只有static成员和函数
11、“怪异的循环模板模式” (curiously recurring template pattern,CRTP)
在条款49中提到。
意图:使用派生类作为模板参数特化基类。CRTP不是多态,多态是动态绑定,CRTP是静态编译期绑定。如果想在编译期确定通过基类来得到派生类的行为,CRTP便是一种独佳选择,它是通过派生类覆盖基类成员函数来实现静态绑定的。
示例代码:
class derived :public base<derived> { // attributes and behaviors } template <classDerived> struct base { void interface() { // 转换为子类指针,编译期将绑定至子类方法 static_cast<Derived*>(this)->implementation(); } static void static_interface() { // 编译期将绑定至子类方法 Derived::static_implementation(); } // 下面两个方法,默认实现可以存在,或者应该被继承子类的相同方法覆盖 void implementation(); static void static_implementation(); }; // The Curiously Recurring Template Pattern(CRTP) struct derived_1 : base<derived_1> { // 这里子类不实现,将使用父类的默认实现 //void implementation(); // 此方法将覆盖父类的方法 static void static_implementation(); }; struct derived_2 : base<derived_2> { // 此方法将覆盖父类的方法 void implementation(); // 这里子类不实现,将使用父类的默认实现 //static void static_implementation(); };
英文链接:
http://en.wikibooks.org/wiki/More_C++_Idioms/Curiously_Recurring_Template_Pattern
12、派生类中定义基类的虚函数需要注意的事项
在条款53中介绍了一个派生类定义基类中虚函数少了const引发的问题。
如果我们决定改写基类所提供的虚拟函数,那么派生类所提供的新定义,其函数型别必须完全符合基类所声明的函数原型,包括:参数列、返回型别、常量性(const-ness)。当派生类中参数列和返回类型有一个不一样时编译器会出错,当常量性改变时,例如条款中将平派生类中少了const时,会重新定义函数,此时会造成当调用const子类时,只会调用基类的函数,而不会调用子类的。
有一点需要注意:
“返回型别必须完全吻合” 这一规则有个例外:当基类的虚拟函数返回某个基类形式(通常是pointer或reference)时:派生类中的同名函数便可以返回该基类所派生出来的型别,例如:
class Base{ public: virtual Base * clone() const; }; class Derived: Base { public: virtual Derived * clone() const; };
可以参考http://www.cnblogs.com/ziyoudefeng/archive/2012/03/20/2407659.html