考虑以下代码:
#include <iostream>
struct Thing {
void foo(bool b = true) {
std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
}
};
struct Blob : Thing { };
struct Event {
void execute(Thing& thing) { thing.foo(); }
};
int main() {
Blob blob;
Event event;
event.execute(blob);
}
输出:
Thing::foo() called with b = true.
假设我们想要输出:
Thing::foo() called with b = false.
当
Thing
是 Blob
类型(以及此处未提及的 Thing
的许多其他派生类)时,但仅当从 Event
调用时,以及从 Event
派生的任何类。
过载解决方案:
struct Event {
void execute(Thing& thing) { thing.foo(); }
void execute(Blob& blob) { blob.foo(false); }
};
不是理想的解决方案,因为
Thing
的许多其他派生类需要此类重载(并且此类派生类的列表将随着程序的发展而不断增加
所以模板元编程解决方案也不会是理想的)。
我想到的一个方案是引入虚方法:
struct Thing {
void foo(bool b = true) {
std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
}
virtual void fooDuringEvent(bool b = true) { foo(b); }
};
struct Blob : Thing {
void fooDuringEvent(bool = true) override { foo(false); }
};
struct Event {
void execute(Thing& thing) { thing.fooDuringEvent(); }
};
这行得通,但是很容易在需要的时候错误地调用
foo()
而不是fooDuringEvent()
,例如
struct Task : Event {
void execute(Thing& thing) {
// Stuff
thing.foo(); // Oops!
// Other stuff
}
};
那么处理这个问题的最佳解决方案是什么?
如果你需要
Thing
根据调用者的不同表现不同,那么你需要告诉它调用者是谁。
struct Thing {
enum {CALLER_NOT_EVENT, CALLER_IS_EVENT} Caller;
void foo(Caller callerIsEvent, bool b = (bool)callerIsEvent) {
std::cout << "Thing::foo() called with b = " << std::boolalpha << b << ".\n";
}
};
struct Blob : Thing { };
struct Event {
void execute(Thing& thing) { thing.foo(CALLER_IS_EVENT); }
};
您也可以使用模板或
typeid
玩游戏,但在我看来,显式枚举更简洁、更容易。
利用 Mooing Duck 的想法,我想出了这样的东西:
#include <iostream>
struct Event;
struct Thing {
template <typename T> void foo (T& t, bool b = true) { fooBasic(b); }
virtual void foo(Event&, bool b = true) { fooBasic(b); }
private:
virtual void fooBasic(bool b = true) { // Cannot be called from Event.
std::cout << "Thing::fooBasic() called with b = " << std::boolalpha << b << ".\n";
}
};
struct Blob : Thing {
void foo(Event&, bool = true) override { fooBasic(false); }
void fooBasic(bool b = true) override {
std::cout << "Blob::fooBasic() called with b = " << std::boolalpha << b << ".\n";
}
};
struct Event {
void execute(Thing& thing) { thing.foo(*this); } // 'thing.foo();' will not compile.
};
int main() {
Blob blob;
Event event;
event.execute(blob);
}