我有一个基类Base
和一个继承它的类Derived
。类Base
有一个虚函数returnPtrToSelf()
,它返回一个指向自身的指针。 Derived
的原始成员函数derivedFunc()
Base
没有。
#include <iostream>
class Base {
public:
virtual Base* returnPtrToSelf() {
return this;
}
};
class Derived : public Base {
public:
void derivedFunc() {
std::cout << "i am derived" << std::endl;
}
}
int main() {
Derived d;
d.derivedFunc(); // works
d.returnPtrToSelf()->derivedFunc(); // ERROR
((Derived*)d.returnPtrToSelf())->derivedFunc(); // works
}
除非我实施Derived
自己的returnPtrToSelf()
并返回Derived*
,否则错误不会消失。
我正在制作很多派生类,并认为为每个派生类实现此函数的原始版本是很繁琐的。除了这种乏味的方式之外,还有更方便的方法来解决这个错误吗?
答案 0 :(得分:1)
不,没有。如果derivedFunc
确实存在从Base
继承的任何东西,那么这应该反映在Base
中:
struct Base {
virtual void func() = 0;
};
struct Derived : Base {
void func() override { std::cout << "i am derived" << std::endl; }
};
Base* b = new Derived;
b->func();
如果derivedFunc
仅 适用于Derived
,那么无论如何都无法从Base
访问它。如果Base
改为AnotherDerived
,该怎么办?在您确实需要致电derivedFunc
的情况下,只需让您的功能采用Derived*
(或Derived&
)代替Base*
(或Base&
)
作为最后的手段,如果确实存在某些情况,您绝对需要在derivedFunc
上唯一地呼叫Derived
,那么总是存在:
void maybeCallDerivedFunc(Base* b) {
if (auto d = dynamic_cast<Derived*>(b)) {
d->derivedFunc();
}
}
答案 1 :(得分:0)
“我正在制作很多派生类,并认为为每个派生类实现此函数的原始版本是很繁琐的。除了这种单调乏味的方法之外,还有更方便的方法来修复错误吗?”
我说这是使用Template Method Pattern的经典案例:
class Base {
public:
void func() {
funcImpl();
}
virtual ~Base() {}
protected:
Base() {}
virtual void funcImpl() = 0;
};
class DerivedA : public Base {
public:
DerivedA() {}
protected:
void funcImpl() {
// DerivedA special implementation
}
};
class DerivedB : public Base {
public:
DerivedB() {}
protected:
void funcImpl() {
// DerivedB special implementation
}
};
主要呼叫看起来像
int main() {
DerivedA dA;
DerivedB dB;
dA.func();
dB.func();
}
如果从Base
派生的每个类都应该为Base::func()
中正在进行的更复杂的逻辑贡献一些专门的部分,那么这一点特别有用。
这可以通过使用模板化基类(不需要vtable开销)的类似方式实现,并且仅封装在main()
函数中应用的强制转换:
template<typename Derived>
class Base {
public:
void func() {
static_cast<Derived*>(this)->funcImpl();
}
protected:
Base() {}
};
class DerivedA : public Base<DerivedA> {
public:
DerivedA {}
protected:
friend class Base<DerivedA>;
void funcImpl() {
// DerivedA special implementation
}
};
class DerivedB : public Base<DerivedB> {
public:
DerivedB {}
protected:
friend class Base<DerivedB>;
void funcImpl() {
// DerivedB special implementation
}
};
这也是众所周知的CRTP - &gt; 奇怪的重复模板模式。