C++设计:重载/覆盖许多函数,清理方法?

mas*_*coj 5 c++ oop overriding overloading

我试图在这里实现的情况是一个Base类,它有一个函数(让我们称之为modify_command),它几乎可以接受许多不同的类型,因此派生类可以根据需要实现modify_command函数.现在我在基类中有这些行:

class Base 
{
    template<typename Command>
    void modify_command(Command cmd)
    { 
        std::cout << "Modify command called with unimplemented command type:" << typeid(cmd).name();
    }

    virtual void modify_command(SpecificCommandA cmd)
    {
         modify_command<SpecificCommandA>(cmd); // Calls the templated function
    }

    virtual void modify_command(SpecificCommandB cmd)
    {
         modify_command<SpecificCommandB>(cmd); // Calls the templated function
    }

    // etc.
};
Run Code Online (Sandbox Code Playgroud)

然后在派生类中:

class Derived : public Base
{
    virtual void modify_command(SpecificCommandA cmd)
    {
        cmd.x = 1;
        cmd.y = 2;
    }
}
Run Code Online (Sandbox Code Playgroud)

显然虚拟模板函数不是可能的,所以在某种形式下,我将不得不列出函数声明,以便进行多种参数可能性,这肯定会使类定义混乱,并且可能使其他命令类型变得困难(随着时间的推移)被处理

具有模板化函数的目的是为了编译这种情况而无需定义modify_command(SpecificCommandC)来记录错误:

Base * base = new Derived();
SpecificCommandA a;
SpecificCommandB b;
SpecificCommandC c;
base->modify_command(a); //Set's x and y
base->modify_command(b); //Outputs that command type is unimplemented
base->modify_command(c); //Outputs that command type is unimplemented
Run Code Online (Sandbox Code Playgroud)

我真的很讨厌我的工作方式,有没有人建议如何清理/重新实现?随着软件的成熟,命令数量将继续增长,因此必须具备可扩展性.

编辑:语法

sky*_*ack 1

不幸的是,可以解决您的问题的是虚拟模板方法,这是不可能的。

下面是一个引入 C++ 世界的更C 风格的解决方案,可以解决该限制:

#include<unordered_map>
#include<functional>
#include<memory>
#include<iostream>
#include<utility>

struct BaseCommand {
    static int counter;
};

int BaseCommand::counter = 0;

template<class T>
struct Command: BaseCommand {
    static int type() {
        static const int t = ++counter;
        return t;
    }
};

struct SpecificCommand1: Command<SpecificCommand1> {};
struct SpecificCommand2: Command<SpecificCommand2> {};

class Base {
    struct Handler {
        virtual void operator()(BaseCommand &cmd) = 0;
    };

    template<typename T>
    struct THandler: Handler {
        std::function<void(T)> func;
        void operator()(BaseCommand &cmd) override {
            func(static_cast<T&>(cmd));
        }
    };
protected:
    template<typename T>
    void assign(std::function<void(T)> f) {
        auto handler = std::make_unique<THandler<T>>();
        handler->func = f;
        handlers[T::type()] = std::move(handler);
    }

public:
    template<typename Command>
    void modifyCommand(Command cmd) {
        auto it = handlers.find(Command::type());
        if(it == handlers.end()) {
            std::cout << "Modify command called with unimplemented command type: " << Command::type();
        } else {
            auto &h = *(it->second);
            h(cmd);
        }
    }

private:
    std::unordered_map<int, std::unique_ptr<Handler>> handlers;
};

class Derived: public Base {
public:
    Derived() {
        std::function<void(SpecificCommand1)> f =
            [](SpecificCommand1) {
                std::cout << "handler for SpecificCommand1" << std::endl;
            };

        assign(f);
    }
};

int main() {
    Base *b = new Derived;
    b->modifyCommand(SpecificCommand1{});
    b->modifyCommand(SpecificCommand2{});
}
Run Code Online (Sandbox Code Playgroud)

基本思想是在运行时为命令提供数字类型(可以使用 CRTP 习惯用法 - 请参阅BaseCommand模板Command类来完成)。
有了这个可访问的值,就需要创建一个类型擦除处理程序来处理您想要为其提供特定实现的命令(请参阅assignHandler/ THandler)。
一旦正确设置了所有部分,您只需在派生类中设计和初始化这些处理程序即可。因为它可以使用 来完成std::function,您可以使用 lambda、公共或私有成员方法、静态方法等作为处理程序。有关更多详细信息,
请参阅 的构造函数。Derived