2013-07-03 87 views
2

所以我一直对D感兴趣一段时间了,我前段时间对它感到困惑。我已经开始重新审视它,并且我确实喜欢它试图实现的目标,但是我对我的一个最喜欢的C++设计选项非常虚惊......。私有继承和非虚拟接口

我喜欢这种设计,它允许在继承层次的“顶部”进行事前和事后条件检查,记录和资源管理。这允许设计者指定一组相关类的所有通用功能,并将类的可定制部分分解为非常小的功能。它还减少了需要写入子类的功能数量。另外,因为虚拟扩展点是私有的,所以它不会污染接口,或者允许用户直接调用实现特定的函数(这非常关键)。

有没有办法在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; 

} 
+0

任何人都知道为什么语法突出显示对代码示例不起作用? – Dennis

+1

我不认为我曾经见过在stackoverflow上的任何D代码中的语法突出显示。 –

回答

2

当然。对于非虚拟成员函数,要么使它成为final(因此编译器可以优化其虚拟性),或者对其进行模板化,然后确保它是非虚拟的,因为模板函数永远不是虚拟的。为了对没有模板参数的函数进行模板化,只需给它一个空的模板参数列表即可。例如

void setChip(RxChip chip) {...} 

成为

void setChip()(RxChip chip) {...} 

而对于虚函数,只是使它protected。目前,privatepackage永远都不是虚拟的,所以如果你想要一个函数是虚拟的,你需要使它成为publicprotected,并且使它成为protected,它不能被公共API访问。你不能像C++那样全力以赴地完成它,但可以说,它并不真正为你买东西,因为重写的函数仍然可以被它所在的类所调用。所以,所有的构造它private所做的是让你不能调用基类的版本(通常是纯粹的虚拟/抽象)。

但是,我会指出,如果你想要的只是契约,D的inout块支持多态。所以,你甚至可能不需要NVI。在那个时候,你只需要基类函数inout就可以得到你想要的契约和契约,并且当派生函数被调用时它们会被调用。这只适用于你想要的前置条件和后置条件,但是它在某些情况下可以避免使用NVI。

+0

对于契约,'in'在多态性方面效果不好,因为它只执行最大派生的'in'块。尽管如此,“out”工作正常,与NVI一样。 – 2013-07-04 00:28:43

+0

所以我想只是考虑一下,我应该使用保护而不是私人的,那么它应该没问题。另外感谢您对合同的了解......我从中得出的结论是,我应该在合同中使用NVI,然后我可以在受保护的扩展点功能上签出多份合同。谢谢小伙子们。 – Dennis