);{} //缺省实现码什么也没做 ... }; class SpecialWindow:public Window{ public: virtual void blink(){...}; //blink做某些事 ... }; ... typedef std::vector
> VPW; VPW winPtrs; ... //容器,内含Window指针,指向所有可能的派生类对象 for(VPW::iterator iter = winPtrs.begin(); iter != winPtrs.end();++iter){ (*iter)->blink(); }
#3.如果转型无可避免,请将它隐藏在函数背后,这样客户调用该函数时,不需要将
转型动作放入它们的代码里,保证了代码的封装性和易维护性。
#4.尽量用C++-style的转型替换旧式转型(构造函数除外),因为
(1).它们很容易在代码中辨别出来,因此简化了“找出类型系统破坏点”的过程。
(2).转型动作分门别类,因此更有利于编译器找出错误的运用。
____________________________________________________________________________________________________________________________________
条款28:若返回 handles 指向对象内部成分,请保证返回值 const 约束大于等于成员函数
#1.References, 指针和迭代器通通都是 handles,用来取得某个对象。
#2.若返回handles指向内部对象,并且成员函数是const,请保证该返回值也是const 。
class Point{
public:
Point(int x, int y);
...
void setX(int newVal);
void setY(int newVal);
...
};
struct RectData{
Point ulhc;
Point lrhc;
};
class Rectangle{
...
private:
std::tr1::shared_ptr
pData;
Point& upperLeft()const{return pData->ulhc;}
Point& lowerRight()const{return pData->lrhc;}
...
};
Point coord1(0,0);Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperLeft().setX(50);
//这里返回的handles可以改变,但与upperLeft const()成员函数的本意是相反的。
//所以应改成:
class Rectangle{
...
private:
...
const Point& upperLeft()const{return pData->ulhc;}
const Point& lowerRight()const{return pData->lrhc;}
...
};
//这样就可以在保证读写权的同时禁止涂写权。
【本条为个人观点:】
#3.对于返回值为自定义(或系统定义)类型的non-const成员函数,返回内部成员
变量的handles(non-const)表示希望该内部变量是public,而对于返回值为内置
类型的成员变量,则该使用pass-by-valued的getXXX()函数和setXXX(X)来分别
区分读写行为。
例如:
//当upperLeft(),lowerRight()为non-const时:
class Rectangle{
...
private:
...
Point& upperLeft(){return pData->ulhc;}
Point& lowerRight(){return pData->lrhc;}
...
};
Point coord1(0,0);Point coord2(100, 100);
Rectangle rec(coord1, coord2);
//我们可以如下这样用函数统一接口设置值和得到值:
rec.upperLeft().setX(50);
int val = rec.lowerRight().getY();____________________________________________________________________________________________________________________________________
条款29:为”异常安全“而努力是值得的
#1.异常安全函数即使发生异常也不会泄露资源或允许任何数据败坏。
这样的函数区分三种可能的保证:基本型,强烈型,不抛异常性。
(1).基本型:异常抛出后,class一切约束条件满足,程序内事物处于一种有效的状态中。
(2).强烈保证型:异常抛出后,程序状态不改变,函数回到调用前的状态。
(3).不抛异常型:保证不抛出任何异常,对内置类型(int,指针,等)身上的所有操作
都提供nothrow保证。
(任何使用动态内存的东西在无法满足内存需求下,都会抛出bad_alloc异常)
#2.除非调用传统非安全异常安全码,否则应保证异常安全,因为传统非异常安全码
不具备异常安全性,所以任何调用它的代码都不具备异常安全性,因此为其撰写
异常安全码是么有任何意义的。
#3.”强烈保证“往往能够以 copy-and-swap实现出来。
//一个用copy-and-swap的示例:
struct PMImpl{ //PMImpl = PrettyMenu Impl
std::tr1::shared_ptr
bgImage;
int imageChanges;
};
class PrettyMenu{
...
private:
Mutex mutex;
std::tr1::shared_ptr
pIml;
};
void PrettyMenu::changeBack(std::istream& imgSrc)
{
using std::swap;
Lock ml(&mutex); //获得mutex的副本数据
std::tr1::shared_ptr
pNew(new PMImpl(*pImpl)); pNew->bgImage.reset(new Image(imgSrc)); //修改副本 ++pNew->ImageChanges; swap(Impl, pNew); //置换(swap)数据,释放mutex } //,但”强烈保证“ 并非对所有函数都具有可实现或具备实现意义:
(1).因为如copy-and-swap这样的强烈保证往往会耗费更多的时间和空间,为了
保证更好的效率,应以”基础保证“来替换,这样才更具现实意义。
(2).当函数对”非局部性数据”有影响时,提供强烈保证就很难了。
void someFunc{
... //对local状态做一份副本
f1();
f2();
... //将修改后的状态置换过来
}
//假设someFunc对“局部数据”提供