所以我对 D 感兴趣已经有一段时间了,而且不久前我还搞过它。我开始再次审视它,我真的很喜欢它想要实现的目标,但我对我最喜欢的 C++ 设计选项...非虚拟接口(interface)感到疑虑。
我喜欢这种设计的地方在于,它允许在继承层次结构的“顶部”进行前置和后置条件检查、日志记录和资源管理。这允许设计者指定一组相关类的所有公共(public)功能,并将类的可定制部分分解为非常小的函数。它还减少了需要在子类中编写的功能量。另外,由于虚拟扩展点是私有(private)的,因此它不会污染接口(interface),也不会允许用户直接调用特定于实现的函数(这非常关键)。
有没有办法在 D 中实现这一点?
C++ 示例(未经测试、未编译...仅供说明)。
class Radio{
public:
Radio( std::string id, Station defaultStation, RxChip chip)
:defaultStation(defaultStation),
id(id),
chip(chip){
}
void turnOn() {
log.trace("Radio turned on: id:[%s]", id.c_str());
doEnableRx();
doPostEnable();
setToStation(defaultStation);
}
void turnOff(){
log.trace("Radio turned off: id:[%s]", id.c_str());
doDisableRx();
doPowerOff();
}
void tune(){
log.trace("Tuning");
findAllStations();
}
void setToStation(Station target){
logStationChange(target);
doSetRxChipPassFilter(target);
}
void setChip(RxChip chip) {
rxChip = chip;
}
RxChip getChip() {
return rxChip;
}
private:
// doesn't start with "do" as this is considered a "normal" virtual function.
virtual void findAllStations(){
chip.setFrequency(chip.getLowFreq());
setChipToNextTunedPoint();
Station stat( chip.getFrequency(), tunedStations.size() );
tunedStations.push_back(stat);
}
virtual bool setChipToNextTunedPoint() {
if(chip.isTuned()) {
while( isTuned && chip.getFrequency() < chip.getHighFreq() )
chip.incrementFreq();
}
while( !chip.isTuned() && chip.getFrequency() < chip.getHighFreq() )
chip.incrementFreq();
return chip.isTuned();
}
// "do" functions are considered mandatory extension points for sub-classes
virtual void doEnableRx() = 0;
virtual void doPostEnable() = 0;
virtual void doDisableRx() = 0;
virtual void doPowerOff() = 0;
virtual void doSetRxChipPassFilter(Station target) = 0
{
//default implementation but it must be specified for use by sub-class.
chip.setFrequency(target.getLowFreq());
while( !chip.isTuned() && chip.getFrequency() < station.getHighFreq() ) {
chip.incrementFreq();
}
}
Station defaultStation;
std::vector<Station> tunedStations;
RxChip chip;
}
最佳答案
当然。对于非虚拟成员函数,要么将其设为final
(以便编译器可以优化其虚拟性),要么将其模板化,然后保证它是非虚拟的,因为模板函数永远不是虚拟的。为了模板化一个没有模板参数的函数,只需给它一个空的模板参数列表。例如
void setChip(RxChip chip) {...}
变成了
void setChip()(RxChip chip) {...}
对于虚函数,只需将其保护
即可。目前,private
和 package
从来都不是虚拟的,因此如果您希望函数是虚拟的,则需要将其设为 public
或 protected
,并且通过使其成为protected
,公共(public) API 无法访问它。你不能像在 C++ 中那样全力以赴地使其成为私有(private)的,但可以说,这并没有真正给你带来任何好处,因为重写函数仍然可以由该类调用因此,将其设置为 private
所做的就是将其设置为使您无法调用基类版本(无论如何,基类版本通常是纯虚拟/抽象的)。
但是,我要指出的是,如果您想要的只是合约,D 的 in
和 out
block 支持多态性。因此,您甚至可能不需要 NVI。那时,您只需让基类函数具有 in
和 out
block ,其中包含您想要的任何 in 合约和 out 合约,并且当派生函数被调用。这仅适用于您想要的前置条件和后置条件的断言,但在某些情况下不需要 NVI。
关于inheritance - 私有(private)继承和非虚拟接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17444449/