将派生类方法链接到基类方法

时间:2016-06-16 12:01:19

标签: c++ method-chaining

我正在编写一个带有可链接方法的库。

class Base {

  protected:
    int stepper=0;

  public:
    Base& baseMethod( void ) {
     Serial.println( stepper );
     return *this; 
    }
    virtual Base& derivedMethod( void ) =0;
    virtual Base& anotherDerivedMethod( void ) =0;
};

class Derived1 : public Base {

  public:
    Derived1& derivedMethod( void ) {
      stepper += 1;
      return *this;
    }

    Derived1& anotherDerivedMethod( void ) {
      stepper -= 1;
      return *this;
    }
};

class Derived2 : public Base {

  public:
    Derived2& derivedMethod( void ) {
      stepper += 2;
      return *this;
    }

    Derived2& anotherDerivedMethod( void ) {
      stepper -= 2;
      return *this;
    }

    Derived2& specialMethod( void ) {
      stepper *= 2;
      return *this;
    }
};

正如您所看到的,baseMethod()会返回对Base课程的引用,因此我不希望能够链接derivedMethod()anotherDerivedMethod()因为Base类不应该访问任何派生方法。

但是,在我的测试代码中(为Arduino编写):

Derived1 myDerived1;
Derived2 myDerived2;

void setup() {

  Serial.begin( 9600 );

  // as expected, these work:

  myDerived1.derivedMethod().baseMethod();  // prints 1
  myDerived1.derivedMethod().derivedMethod().baseMethod();  // prints 3
  myDerived1.anotherDerivedMethod().baseMethod();  // prints 2
  myDerived1.anotherDerivedMethod().derivedMethod().baseMethod();   // prints 2

  myDerived2.specialMethod().baseMethod();  // prints 0
  myDerived2.specialMethod().derivedMethod().baseMethod();  // prints 2
  myDerived2.derivedMethod().specialMethod().baseMethod();  // prints 8

  // I wouldn't expect these to work, but I'm glad they do!

  myDerived1.baseMethod().derivedMethod();  // prints 2
  myDerived1.baseMethod().anotherDerivedMethod();  // prints 3

  myDerived2.baseMethod().derivedMethod();  // prints 8
  myDerived2.specialMethod().baseMethod().derivedMethod();  // prints 20

  // and as expected, these don't work:  

  myDerived2.baseMethod().specialMethod();  // prints 22
  myDerived2.baseMethod().derivedMethod().specialMethod();  // prints 24
}

void loop() { }

可以derivedMethod()anotherDerivedMethod()baseMethod(),但我可以链{{1}对它来说。

specialMethod()

我能看到的唯一区别是method_chaining.ino:76:27: error: 'class Base' has no member named 'specialMethod' 类定义中没有提及specialMethod()。这就是为什么它不起作用?

如何将派生类方法链接到基类方法?

2 个答案:

答案 0 :(得分:1)

虚函数的重点是能够从基本引用或指针访问派生的功能 - 这就是多态的工作方式。 Base引用具有作为其动态类型派生的底层。事实上,因为你的Base是抽象的(即具有纯虚方法),它的动态类型本身不能(除了一些有限的边缘情况,例如在破坏期间),因为你通常不能创建一个抽象的对象类型。

出于同样的原因,调用纯虚方法 来解析(除了一些有限的情况)对派生类的调用。

上述情况的一个例外是当您尝试从析构函数调用纯虚方法时,它可能会导致运行时崩溃('纯虚方法称为')。

答案 1 :(得分:1)

问题是baseMethod的返回类型是Base,并且在派生类中没有覆盖它。调用derived2.baseMethod().specialMethod()时,编译器必须检查返回的对象的类(声明的静态类型Base)是否包含成员函数specialMethod()。即使动态类型包含它,它也会失败,但这在编译时是不可知的。

要使您的示例正常工作,您必须以与对其他成员函数相同的方式覆盖派生类中的函数。但是,只要静态类型是派生类型,所有这些只能起作用,因为编译器只检查它。如果您不打算通过baseFunction指针以多态方式调用Base,则可以使用静态多态性:

template<typename T>
class Base {
  public:
    T& baseMethod( void ) {
         return *static_cast<T*>(this);
    }

    virtual Base& derivedMethod( void ) =0;
    virtual Base& anotherDerivedMethod( void ) =0;
};

class Derived1 : public Base<Derived1> {

  public:
    Derived1& derivedMethod( void ) {
      return *this;
    }

    Derived1& anotherDerivedMethod( void ) {
      return *this;
    }
};

class Derived2 : public Base<Derived2> {    
  public:
    Derived2& derivedMethod( void ) {
      return *this;
    }

    Derived2& anotherDerivedMethod( void ) {
      return *this;
    }

    Derived2& specialMethod( void ) {
      return *this;
    }
};

这样做的缺点是派生类不共享公共Base<T>父级,因为Base<Derived1> is a different type than Base . To have polymorphism, you have use templates Base`无处不在。

我不确定我是否喜欢这种设计。受保护的成员总是让我认为这是通过继承实现共享,这是你应该避免的。我想