这里钩子函数本身需要检查同样属于类层次结构的数据成员的typeid。所以我为这个类层次结构定义了一个模板方法。这是我遇到的混乱:
void Person::leave() {
// code
hook(); // private virtual
// code
}
void Girl::hook() { // Girl is a derived class of Person, with data member location
// of type Location which itself has a derived class House
// code
location.locationHook(this);// what happens here depends on what kind of location she is in
// code
}
void Location::locationHook(Person* person) {
// Oh oh! This depends on what class person is
}
void House::locationHook(Person* person) {
// Oh oh! This depends on what class person is
}
因此,对于这种情况,我不得不求助于我的原始方法,对每种类型的Person派生类使用typeid(* person)和dynamic_cast以及if语句来定义虚拟locationHook,对吗?
答案 0 :(得分:0)
这是我提出的解决方案。我测试它是否有效,但我不知道它是否得到任何批准(或者它是否会一直有效):
void Person::leave() {
// code
hook();
}
void Person::hook() {
// code
location.locationHook (this);
}
void Girl::hook() {
// code
location.locationHook (this);
}
void Location::locationHook (Person* person) {
// code
person->removeFromLocation();
}
void House::locationHook (Person* person) {
// code
person->removeFromHouse();
}
// removeFromLocation() and removeFromHouse() are also virtual functions of Person
答案 1 :(得分:0)
这是使用双重调度的替代解决方案:
#include <iostream>
#include <list>
struct Person; struct Girl; struct Guy;
struct Location {
virtual void hook (Person*) = 0;
virtual void hook (Girl*) = 0;
virtual void hook (Guy*) = 0;
};
struct House : Location {
virtual void hook (Person*) override;
virtual void hook (Girl*) override {
std::cout << "Girl left the house.\n";
}
virtual void hook (Guy*) override {
std::cout << "Guy left the house.\n";
}
};
struct Person {
Location* location = new House;
void leave() {
// ...
hook();
// ...
}
virtual void invoke_hook (Location*) = 0;
private:
virtual void hook() = 0;
};
struct Girl : Person {
virtual void hook() override {
std::cout << "Girl will leave the house.\n";
location->hook(this);
// ...
}
virtual void invoke_hook (Location* location) override { location->hook(this); } // Double dispatch
};
struct Guy : Person {
virtual void hook() override {
std::cout << "Guy will leave the house.\n";
location->hook(this);
// ...
}
virtual void invoke_hook (Location* location) override { location->hook(this); } // Double dispatch
};
void House::hook (Person* person) {
person->invoke_hook(this); // Double dispatch
}
int main() {
std::list<Person*> people = {new Girl, new Guy};
for (Person* p : people)
p->leave(); // Simple overloads will do the job here.
House* house = new House;
for (Person* p : people)
house->hook(p); // Double dispatch used.
}
输出:
Girl will leave the house.
Girl left the house.
Guy will leave the house.
Guy left the house.
Girl left the house.
Guy left the house.