1. 继承体系中关于对象释放遇到的问题描述 1.1 手动释放 关于时间记录有很多种方法,因此为不同的计时方法创建一个TimeKeeper基类和一些派生类就再合理不过了: class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); ... }; class AtomicClock: public TimeKeeper { ... }; class WaterClock: public TimeKeeper { ... }; class Wrist…
1. 为什么不要重新定义继承而来的非虚函数——实际论证 假设我告诉你一个类D public继承类B,在类B中定义了一个public成员函数mf.Mf的参数和返回类型并不重要,所以假设它们都是void.实现如下: class B { public: void mf(); ... }; lass D: public B { ... } 我们不需要了解B,D或者mf的任何细节,考虑一个类型D的对象x, D x; // x is an object of type D 你会感到很吃惊,如果下面的语句:…
1. 突破思维——不要将思维限定在面向对象方法上 你正在制作一个视频游戏,你正在为游戏中的人物设计一个类继承体系.你的游戏处在农耕时代,人类很容易受伤或者说健康度降低.因此你决定为其提供一个成员函数,healthValue,返回一个整型值来表明一个人物的健康度.因为不同的人物会用不同的方式来计算健康度,将healthValue声明为虚函数看上去是一个比较明显的设计方式: class GameCharacter { public: virtual int healthValue() const;…
关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为这是c++同它们不一样的地方. 假设你已经有一个为股票交易建模的类继承体系,它可以买卖股票等.这些交易的可审计性很重要,所以每次交易对象被创建的时候,需要在审计日志中创建一个合适的记录.这看上去是解决问题的合理方法: class Transaction { // base class for all…
从一开始就让我们简化这次的讨论.你有两类你能够继承的函数:虚函数和非虚函数.然而,重新定义一个非虚函数总是错误的(Item 36),所以我们可以安全的把这个条款的讨论限定在继承带默认参数值的虚函数上. 1. 虚函数是动态绑定的,而默认参数是动态绑定的 在这种情况下,这个条款的验证就相当直接了:虚函数是动态绑定的,而默认参数值是静态绑定的. 这是什么?你说你不堪重负的脑袋已经忘记了动态绑定和静态绑定之间的区别?(为了好记,静态绑定也叫做早绑定(early binding),动态绑定也叫做晚绑定(l…
Item 50中解释了在什么情况下你可能想实现自己版本的operator new和operator delete,但是没有解释当你实现的时候需要遵守的约定.遵守这些规则并不是很困难,但是它们其中有一些并不直观,所以知道这些规则是什么很重要. 1. 定义operator new的约定 1.1 约定列举 我们以operator new开始.实现一个一致的operator new需要有正确的返回值,在没有足够内存的时候调用new-handling函数(见Item 49),并且做好准备处理没有内存可分配…
1. 显示接口和运行时多态 面向对象编程的世界围绕着显式接口和运行时多态.举个例子,考虑下面的类(无意义的类), class Widget { public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void normalize(); void swap(Widget& other); // see Item 25 ... }; 考虑下面的函数(同样没有意义), void doProcessin…
1. C++0x的历史渊源 C++标准——也就是定义语言的文档和程序库——在1998被批准.在2003年,一个小的“修复bug”版本被发布.然而标准委员会仍然在继续他们的工作,一个“2.0版本”的C++标准预计在2009年被发布(虽然所有的工作很有可能在2007年底被完成).直到现在,发布下一版C++的预计年份还没有被确定,这就解释了为什么人们把下一版C++叫做“C++0x”——C++的200x年版本. C++0x可能会包含一些有趣的新的语言特性,但是大多数新C++功能将会以标准库附加物的形式被…
1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to self. 这看上去是愚蠢的,但这是合法的,所以请放心,客户端是可以这么做的.此外,自身赋值也并不总是很容易的能够被辨别出来.举个例子: a[i] = a[j]; // potential assignment to self 上面的代码在i和j相等的情况下就是自我赋值,同样的,看下面的例子: *px =…
1.默认构造函数介绍 在设计良好的面向对象系统中,会将对象的内部进行封装,只有两个函数可以拷贝对象:这两个函数分别叫做拷贝构造函数和拷贝赋值运算符.我们把这两个函数统一叫做拷贝函数.从Item5中,我们得知,如果需要的话编译器会为你生成这两个拷贝函数,并且编译器生成的版本能够精确的做到你想做的:它们拷贝了对象的所有数据. 2.自己实现构造函数有可能出现问题 当你声明自己的拷贝函数的时候,你就会向编译器表示,你对编译器生成版本的拷贝函数有些地方不是很喜欢.编译器看上去生气了,它们会以一种奇怪的方式…