C#存在同样的问题,但不适用于C ++。
class Base
{
void dispatch()
{
if (newStyleHasBeenOverridden()) //how to find this out?
newStyle(42);
else
oldStyle(1, 2);
}
virtual void oldStyle(int, int) { throw "Implement me!"; }
virtual void newStyle(int) { throw "Implement me!"; }
}
class Derived:public Base
{
void newStyle(int) override
{
std::cout<<"Success!";
}
}
答案 0 :(得分:2)
警告:此解决方案不是跨平台的,因为它依赖于GCC扩展和一些未定义的行为。
GCC允许语法通过说this
从this->*&ClassName::functionName
的vtable中获取指向该函数的指针。实际使用它可能不是一个好主意,但无论如何这是一个演示:
#include <iostream>
class Base {
public:
void foo() {
auto base_bar_addr = reinterpret_cast<void*>(&Base::bar);
auto this_bar_addr = reinterpret_cast<void*>(this->*&Base::bar);
std::cout << (base_bar_addr == this_bar_addr ? "not overridden" : "overridden") << std::endl;
}
virtual void bar() { };
};
class Regular : public Base { };
class Overriding : public Base {
public:
virtual void bar() { };
};
int main() {
Regular r;
r.foo();
Overriding o;
o.foo();
}
后人:
&Base::bar
一样,所以你总是认为它没有被覆盖。答案 1 :(得分:2)
这是一个设计问题。
然而,为了回答实际问题,有几种方法可以在不重新设计的情况下完成此任务(但实际上,应重新设计它)。
一个(可怕的)选项是调用newstyle方法并捕获未被覆盖的异常。
void dispatch() {
try {
newStyle(42);
} catch (const char *) {
oldStyle(1, 2);
}
}
如果覆盖了newStyle,则会调用覆盖。否则,基本实现将抛出,哪个调度将捕获然后回退到oldStyle。这是对例外的滥用,而且表现不佳。
另一种(稍微不那么糟糕)的方法是将newStyle的基本实现转发到oldStyle。
void dispatch() {
newStyle(42);
}
virtual void newStyle(int) { oldStyle(1, 2); }
virtual void oldStyle(int, int) { throw "implement me"; }
这至少会朝着更好的设计方向发展。继承点是允许高级代码能够交替使用对象,而不管它们的专业化程度如何。如果调度必须检查实际的对象类型,那么您违反了Liskov替换原则。 Dispatch应该能够以相同的方式处理所有对象,并且行为的任何差异都应该来自被覆盖的方法本身(而不是覆盖的存在)。
答案 2 :(得分:0)
使事情更简单,调度决定由Derived
类完成。
抽象Base
类基本上只是一个“接口”,其中Derived
类应实施所有 virtual
功能。
这个问题听起来像XY问题。
我认为这就是你想要的:
class Base // abstract class
{
virtual void oldStyle(int, int) = 0; // pure virtual functions
virtual void newStyle(int) = 0; // needs to be implemented
};
class Derived:public Base
{
public:
Derived(bool useNewStyle): _useNewStyle(useNewStyle) {}
void newStyle(int) { std::cout << "new style"; }
void oldStyle(int, int) { std::cout << "old style"; }
void dispatch()
{
if (_useNewStyle) {
newStyle(42);
return;
}
oldStyle(1, 2);
return;
}
private:
bool _useNewStyle = false;
};
Derived d(true); // use new style
d.dispatch(); // "new style"