//—————————15/04/24—————————-
//#35 考虑virtual函数以外的其他选择
{
/*
1:通常情况下对于有变动的东西,我们都会设计成virtual函数,然后由子类来继承,并重新实现,
但是,由于这个惯性思维,,成了弱点。因为我们这样就没有想过别的实现方法。
2:用Non-Virtual Interface来代替virtual函数。
1>把virtual函数设计成private,并使用别的public函数调用。这里有一个很关键的一点:
private virtual函数能实现多态么?答案是肯定的。尽情地重定义吧。
2>在调用virtual函数的前后可以加上一些自己的控制,比如上锁,记录等等一切你想做的。
3>其实也不一定必须是private的,自己看情况定义吧。
3:使用Strategy模式:
1>当你需要virtual函数时,可以考虑存储一个仿函数对象,然后在一个public函数中调用这个
仿函数。
2>这个仿函数内部的操作不应该依赖于类的内部细节,不然还是乖乖用virtual函数来的好。
3>这时你会发现,可以动态地改变要调用的函数,比如一个计算血量值的函数,可以一开始调用
正常版本的,当角色中毒什么的,就换一个计算血量的函数。哇!cool。
*/
}
//#36 绝不重新定义继承而来的non-virtual函数
{
/*
前提:D public继承自 B
先看两个准则(前面的条款已经将过的):
1>适用于B对象的每一件事,也使用于D对象,因为每个D对象 is-a B对象。
2>D一定会继承B的non-virtual函数的接口和实现。
所以,如果我们重新定义了一个non-virtual函数:
1>D以public方式继承B,那么当D有一个函数需要重新定义(不变性凌驾特异性),这个函数
应该为virtual的而不是non-virtual的。
2>如果这个函数不需要被重定义(特异性凌驾不变性),那么D久不需要重定义mf,而且它也
不应该尝试这么做。
所以结论是:不要重定义继承而来的non-virtual函数。
*/
}
//#37 绝不重定义继承而来的缺省参数值
{
// 1:看下这两个函数:
class Shape
{
public:
enum ShapeColor{Red, Green, Blue};
virtual void draw(ShapeColor color = Red)const = 0;
};
class Rectangle : public Shape
{
public:
virtual void draw(ShapeColor color = Green)const;
};
/*
这么做的结果就是:当客户使用基类指针,子类对象时,调用的内容是子类的,默认参数确实基类的。
这样子做没有意义,所以问题朝着两个方向发展:
1>你想切换默认参数。
2>你想保留默认参数,但是切换调用的内容。如果子类也要使用相同的参数,那么如果默认参数一改变
基类和子类的都必须改变,所以这很糟糕。
实现起来很简单嘛:
1>想切换参数?定义一个non-virtual函数,然后用virtual的函数调用之,
调用时传入不同的参数就ok了。
2>想切换调用内容?定义一个private virtual函数,然后用带着默认参数的non-virtual函数调用之。
*/
}
//#38 通过复合塑膜出has-a或"根据某物实现出"
{
/*
复合有两种情况:
1>has-a
如果你塑造的对象是世界中的某些事物,比如人、物、汽车等等,那么这样的对象属于应用域,
当复合发生在应用域时,表现出has-a的关系。
2>is-implemented-in-terms-of(根据某物实现出)
如果你塑造的对象是为了实现细节上的人工制品,像缓冲区、互斥锁等,这样的对象属于实现域
这样的复合表现出is-implemented-in-terms-of关系。
具体的例子就是,当你想要实现一个set时,你可能需要在类内含一个std::list,因为你不想
自己写list,这样的关系就是is-implemented-in-terms-of,这个set是根据list实现的
通电话,旅行,重复一个承诺和梦想,