我正在编写一个带有可链接方法的库。
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()
。这就是为什么它不起作用?
如何将派生类方法链接到基类方法?
答案 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`无处不在。
我不确定我是否喜欢这种设计。受保护的成员总是让我认为这是通过继承实现共享,这是你应该避免的。我想