嗯。据我了解,您的设计或解决问题的方法可能是错误的。也许,我们在这里谈论的是XY-Problem。
了解您真正想要实现的目标会非常有趣。
那么,我的下一个观察:我认为你还没有完全理解多态性的含义或者如何正确使用它。
在您的示例代码中,根本没有 多态性。没有虚函数之类的。
而且您的CommandHandler 不是从公共基类派生的。乍一看,CommandHandler 和 Command 之间似乎存在关系。但是没有。只有一个相同的命名。例如 BCommandHandler 也可以有一个process 函数,该函数适用于类型 CommandA。这在某种程度上是一个奇怪的概念。 Handler 和 Command 之间应该有关系。
最好将process 函数作为命令类的一部分。那将是一个更有意义的设计,并且会消除几乎所有的问题。但正如所说:我不知道你为什么选择这样的设计。
接下来,即使我们有一个CommandHandler 的类层次结构并尝试通过CommandHandler 的基类指针调用虚函数,我们仍然有一个基类作为函数的参数指向Command 的指针。
这需要所谓的双重调度功能。因此,被调用对象和给定参数的多态性。不幸的是,C++ 语言不支持双重调度机制。您可以通过使用 GOF 中的 Visitor 模式来模拟它。但众所周知,这种模式难以理解和实现,并且会产生循环引用的问题。在 Andrei Alexandrescu 的“Modern C++ Design: Generic Programming and Design Patterns Applied”中可以找到一个非常好的解决方案。在那里您可以阅读有关非循环访问者模式的信息。很好的解释。
另一种解决方案是使用模板来实现静态/编译时多态性。但是你说你有很多commands。而且我担心你会得到一些实质性的代码膨胀。
但是由于handler 和command 之间存在一些固定关系,您可以使用std::map 和一些RTTI 机制来解决您的问题。还有dynamic_cast
不太好,可能很贵,但可以按以下方式使用:
#include <iostream>
#include <map>
#include <string>
#include <utility>
struct Command { virtual void someDummyVirtualFunctionDoingNothing() {} };
struct CommandA : public Command { int i{ 42 }; };
struct CommandB : public Command { double d{ 43.2 }; };
struct CommandC : public Command { unsigned u = 44u; float f{ 45.6 }; };
struct CommandHandler {
virtual void process(Command*) = 0; // pure virtual function. Make Base class abstract
};
struct CommandHandlerA : public CommandHandler {
void process(Command* com) {
if (CommandA* ca = dynamic_cast<CommandA*>(com))
std::cout << "Command Handler A: " << ca->i << '\n';
}
};
struct CommandHandlerB : public CommandHandler {
void process(Command* com) {
if (CommandB* cb = dynamic_cast<CommandB*>(com))
std::cout << "Command Handler B: " << cb->d << '\n';
}
};
struct CommandHandlerC : public CommandHandler {
void process(Command* com) {
if (CommandC* cc = dynamic_cast<CommandC*>(com))
std::cout << "Command Handler C: " << cc->u << '\t' << cc->f << '\n';
}
};
class Intermediator
{
public:
void delegate(Command* command)
{
const std::string key{ typeid(*command).name() };
if (dispatcher.find(key) != dispatcher.end()) {
dispatcher[key]->process(command);
}
}
// Commands are just dummies and used to get the type
void addDelegate(CommandHandler* handler, Command* command) {
const std::string key{ typeid(*command).name() };
dispatcher[key] = handler;
}
protected:
std::map<std::string, CommandHandler*> dispatcher{};
};
int main() {
// Define instances of command classes
Command* commandA = new CommandA(); // Dummy. Only needed for type deduction
Command* commandB = new CommandB(); // Dummy. Only needed for type deduction
Command* commandC = new CommandC(); // Dummy. Only needed for type deduction
Command* commandAA = new CommandA();
Command* commandBB = new CommandB();
Command* commandCC = new CommandC();
// Define Instances of command handler
CommandHandler* commandHandlerA = new CommandHandlerA();
CommandHandler* commandHandlerB = new CommandHandlerB();
CommandHandler* commandHandlerC = new CommandHandlerC();
// Add delegate function for types.
// All pointers here are pointer to the base classes.
// Here the commands are just dummies and only used to get the type.
Intermediator im{ };
im.addDelegate(commandHandlerA, commandA);
im.addDelegate(commandHandlerB, commandB);
im.addDelegate(commandHandlerC, commandC);
// Call delegate. Please note. The commands are pointers to the abstract base Class
im.delegate(commandAA);
im.delegate(commandBB);
im.delegate(commandCC);
return 0;
}
请注意:拥有内存的原始指针应替换为std::unique_ptr 或其他智能指针。
而且,如上所述,我仍然认为这是错误的设计。
也许抽象工厂可以帮助你。