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;

}
4

1 回答 1

2

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

void setChip(RxChip chip) {...}

变成

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

而对于虚函数,只需 make protected。目前,privateandpackage从来都不是虚拟的,所以如果你想要一个函数是虚拟的,你需要将它设置为publicor protected,并且通过设置它protected,公共 API 无法访问它。您不能像在 C++ 中那样全力以赴private,但可以说,这并没有真正为您带来任何好处,因为覆盖函数仍然可以由它所在的类调用。所以,一切都在做private这样做是为了使您无法调用基类版本(无论如何,这通常是纯虚拟/抽象)。

但是,我要指出,如果您想要的只是合约,那么 Dinout块支持多态性。因此,您甚至可能不需要 NVI。那时,您只需让基类函数拥有inout阻塞您想要的任何 in 合约和 out 合约,并且当派生函数被调用时它们将被调用。这仅适用于您想要的前置和后置条件的断言,但在某些情况下它消除了对 NVI 的需要。

于 2013-07-03T23:05:06.313 回答