我们有这样一个定时器
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不就可以了吗,书上到底想要说的是一个什么问题???
阿神2017-04-17 15:34:45
This is just what we're looking for. A Timer object can be configured to tick with whatever frequency we need, and on each tick, it calls a virtual function. We can need, and on each tick, it calls a virtual function. We cancan> that virtual function so that it examines the current state of the Widget world. Perfect!
根據前文對Timer的描述,可以得知onTick必須是虛函數,因為Timer的衍生類別需要透過重寫onTick來改變這個函數的行為(比方說定義新的Timer時)。 redefine是重寫的意思。
現在Widget需要一個Timer,可能需要重寫Timer的onTick函數來滿足自己的需求,同時從Widget派生出來的類別要無法改變onTick的行為。
讓Widget「擁有」一個onTick有兩種方案:繼承或聚合。
如果採用Widget繼承Timer,onTick可被重寫;但如此的話,Widget的衍生類別也都可以重寫onTick,因為Widget繼承了Timer,且onTick在Timer裡被宣告為虛函數。 (
宣告在非直接基底類別裡的虛函數也可以被重寫,衍生類別無法取消在基底類別中宣告的虛函數,一組虛函數只需要在基底類別宣告為virtual即可) 而聚合則能避免繼承所帶來的這個問題:Widget聚合一個Timer的衍生類,根據需求在衍生類別裡重寫onTick。如書中所舉的例子(WidgetTimer中的onTick聲明時的virtual是多餘的):
class Widget {
private:
class WidgetTimer: public Timer {
public:
virtual void onTick() const;
...
};
WidgetTimer timer;
...
};
非相關:
雖然無法取消虛擬函數,但是可以利用域的巢狀關係隱藏基底類別的虛擬函數,比方說定義一個同名的可呼叫物件。這樣一些特定的呼叫會直接找到這個對象,而不是虛成員函數。但依然
無法阻止重寫。
#include <cassert>
struct Timer {
virtual void onTick() {}
};
struct Widget : Timer {
struct Callable {
void operator()() {}
} onTick;
void bar() {
this->onTick();
onTick();
}
};
struct Derived : Widget {
void onTick() {
assert(false);
}
};
int main() {
Derived obj;
static_cast<Widget &>(obj).onTick();
static_cast<Widget &>(obj).bar();
static_cast<Timer &>(obj).onTick(); // assert failed
return 0;
}