我们有这样一个定时器
class Timer{
public:
explict Timer(int tickFrequency);
virtual void onTick() const;
...
};
然后比较了继承和复合。
继承的代码:
class Widget:private Timer{
private:
virtual void onTick() const;
...
};
然后书上说:
首先,你或许会想设计Widget使它得以拥有derived classes,但同时你可能会想阻止derived classes重新定义onTick。如果Widget继承自Timer,上面的想法就不可能实现,即使是private继承也不可能。
首先,这里说的是重新定义。重定义函数要求基类中的对应函数是非虚的,而给出的代码是虚的。如果说的是重写,我们不想基类中的对应函数被重写就不要讲它声明为virtual不就可以了吗,书上到底想要说的是一个什么问题???
Timer の前述の説明によれば、onTick は仮想関数でなければならないことがわかります。これは、Timer の派生クラスが、この関数の動作を変更するために onTick をオーバーライドする必要があるためです (たとえば、新しい Timer を定義する場合)。 redefineは書き直すという意味です。
ウィジェットにタイマーが必要になったので、独自のニーズに合わせてタイマーの onTick 関数を書き直す必要がある場合があります。同時に、ウィジェットから派生したクラスが onTick の動作を変更できないようにする必要があります。
ウィジェットに onTick を「所有」させるには、継承または集約という 2 つのオプションがあります。
Widget が Timer を継承する場合、onTick はオーバーライドできます。ただし、この場合、Widget は Timer を継承し、onTick は Timer で仮想関数として宣言されるため、Widget の派生クラスも onTick をオーバーライドできます。 (間接基本クラスで宣言された仮想関数もオーバーライドできます。派生クラスは、基本クラスで宣言された仮想関数をキャンセルできません。仮想関数のセットは、基本クラスで仮想として宣言する必要があるだけです。)
集約により、継承によって引き起こされるこの問題を回避できます。ウィジェットは Timer の派生クラスを集約し、必要に応じて派生クラスの onTick をオーバーライドします。本に記載されている例のように (WidgetTimer で onTick を宣言する場合の仮想は冗長です):
リーリー関係ありません:
仮想関数はキャンセルできませんが、フィールドのネストされた関係を使用して、基本クラスの仮想関数を非表示にすることができます。たとえば、同じ名前の呼び出し可能オブジェクトを定義します。このようにして、一部の特定の呼び出しでは、仮想メンバー関数ではなくオブジェクトが直接検索されます。しかし、それでも書き換えを防ぐことはできません。
リーリー