C++ C++;设计:重载/重写许多函数,如何清理?

C++ C++;设计:重载/重写许多函数,如何清理?,c++,oop,overloading,overriding,C++,Oop,Overloading,Overriding,我在这里尝试实现的是一个基类,它有一个函数(我们称之为modify_command),可以接受许多不同的类型,因此派生类可以根据需要实现modify_command函数。 现在我在基类中有一些类似的东西: class Base { template<typename Command> void modify_command(Command cmd) { std::cout << "Modify command called wi

我在这里尝试实现的是一个基类,它有一个函数(我们称之为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.
};
struct CommandBase {};

struct CommandA: CommandBase {};
struct CommandB: CommandBase {};
struct SomeCommandType: CommandBase {};
struct CommandC: CommandBase {};

using AvailableCommmands = meta::list<CommandA, CommandB, SomeCommandType>;
显然,虚拟模板函数是不可能的,因此在某种形式下,我将不得不列出无数参数的函数声明,这肯定会使类定义变得混乱,并可能使处理其他命令类型变得困难(随着时间的推移)

使用模板函数的目的是在这种情况下进行编译,而无需定义modify_命令(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
我真的很讨厌我的工作方式,有没有人对如何清理/重新实施有什么建议?随着软件的成熟,命令的数量将继续增加,因此扩展性是必须的


编辑:语法

我不确定这是否是您想要的,但我正在继续我的想法:

在类型列表/可变参数列表中查找类型的小型元程序。需要确定命令是否是实现的一部分

namespace meta {
template <typename... T> struct list{};
template <typename F, typename T> struct has_type;

template <typename F>
struct has_type<F, list<>> {
  using type = typename std::false_type;
  static constexpr bool value = false;
};

template <typename F, typename... T>
struct has_type<F, list<F, T...>> {
  using type = typename std::true_type;
  static constexpr bool value = true;
};

template <typename F, typename H, typename... T>
struct has_type<F, list<H,T...>> {
  using type = typename std::false_type;
  static constexpr bool value =
    std::is_same<F, typename std::decay<H>::type>::value ? true : has_type<F, list<T...>>::value;
};
}

代码很混乱,这是可以理解的,我相信一定有更好的方法可以做到这一点。

我可能没有完全理解您的问题,但我提出了一个解决方案,解决了如何允许派生类重载的问题,这些派生类将作为模板的“虚拟函数”。 我做了一个小改动:
specificcomanda
specificcomandb
有一个共同的祖先类
Command
,如果在代码中没有,只需创建一个
Command
类,并使用类似于
struct SpecificAPrime:common,specificcomanda{}的东西

首先是守则:

#include <typeindex>
#include <unordered_map>

struct Command { virtual ~Command() {}; };

struct SpecificCommandA: Command {};
struct SpecificCommandB: Command {};
struct SpecificCommandC: Command {};


struct Base {
    virtual ~Base() {}; 

    virtual void modify_command(Command &c, std::type_index); // default

    void modify_command(Command &c) {
        modify_command(c, std::type_index(typeid(c)));
    }
};

template<typename Der, typename SpecC> struct Modifier {
    static void execute(Der &d, Command &c) {
        d.modify_command(static_cast<SpecC &>(c)); 
    }
};

struct Derived: Base {
    using Base::modify_command; // <- Because there are overloads
    virtual void modify_command(SpecificCommandB &);
        // Put here the specific code you want for SpecificCommandB.
        // Note that this can be overriden in derived classes

    void modify_command(Command &c, std::type_index ti) override {
        using callable = void (*)(Derived &, Command &);
        const static std::unordered_map<std::type_index, callable> derived_map =
        {
            { std::type_index(typeid(SpecificCommandB)), Modifier<Derived, SpecificCommandB>::execute }
        };
        auto find_result = derived_map.find(ti);
        if(derived_map.end() == find_result) { Base::modify_command(c, ti); }
        else { (*find_result->second)(*this, c); }
    }
};
#包括
#包括
结构命令{virtual~Command(){};};
结构SpecificCommandA:命令{};
结构SpecificCommandB:命令{};
结构SpecificCommandC:Command{};
结构基{
虚~Base(){};
虚拟void modify_命令(command&c,std::type_index);//默认值
无效修改命令(命令和c){
修改_命令(c,std::type_索引(typeid(c));
}
};
模板结构修改器{
静态无效执行(Der&d、命令&c){
d、 修改_命令(静态_cast(c));
}
};
派生结构:基{
使用Base::modify_命令;//second)(*this,c);}
}
};
其思想如下:因为现在这些命令有一个共同的祖先,并且是多态的,所以可以使用动态多态性来代替模板,包括typeid操作符

现在
modify\u命令(command&)
既不是模板,也不是多态函数,它所做的是找到命令的
type\u索引
,并将其转发给多态函数。多态函数
modify_command(command&,type_index)
的实现在内部有一个type_索引的映射,它们知道如何专门修改该映射。如果给定的
type\u索引
不在映射中,则默认为基类实现,如果
type\u索引
在映射中,则调用映射元素,该元素只是调用给定特定重载的模板函数的实例化

从某种意义上说,这是一个多态类型开关


这里有一个完整的运行示例:

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

这是一个更接近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{});
}
#包括
#包括
#包括
#包括
#包括
结构BaseCommand{
静态整数计数器;
};
int BaseCommand::counter=0;
模板
结构命令:BaseCommand{
静态int类型(){
静态常量int t=++计数器;
返回t;
}
};
结构SpecificCommand1:命令{};
结构SpecificCommand2:命令{};
阶级基础{
结构处理程序{
虚拟void操作符()(BaseCommand&cmd)=0;
};
模板
结构THandler:Handler{
std::函数func;
void操作符()(BaseCommand&cmd)重写{
func(static_cast(cmd));
}
};
受保护的:
模板
无效赋值(标准::函数f){
自动处理程序=std::make_unique();
handler->func=f;
处理程序[T::type()]=std::move(处理程序);
}
公众:
模板
无效修改命令(命令cmd){
auto it=handlers.find(Command::type());
if(it==handlers.end()){

std::无法使用成员函数创建一个特定的命令基类,例如onModifyCommand,它可以修改_命令调用。@kfsone我不确定我是否理解你的意思。我的每个派生类都会以不同的方式修改命令(有时根本不会)。这将如何使我的派生能够指定它自己的修改命令的实现?似乎您想要一个虚拟模板函数的等价物,而不必将派生类中的所有特定重载声明为基类中的虚拟函数。请确认解决此问题的方法。Migh我正在尝试分离实现,这样一个派生类可能有CommandA的处理程序而不是CommandB,另一个类可能有CommandB的处理程序而不是CommandA,还有一个可以处理a和B。我只浏览了一下,但似乎这个解决方案将所有派生类都绑定在一起Ion必须处理列表中的命令?@mascoj:你可能可以借助
动态强制转换
而不是
静态强制转换
内部
do\u on\u modify\u命令
函数来处理这些命令。但是,要使之工作,你必须通过添加至少一个虚拟函数来使
CommandBase
多态化
#include <typeindex>
#include <unordered_map>

struct Command { virtual ~Command() {}; };

struct SpecificCommandA: Command {};
struct SpecificCommandB: Command {};
struct SpecificCommandC: Command {};


struct Base {
    virtual ~Base() {}; 

    virtual void modify_command(Command &c, std::type_index); // default

    void modify_command(Command &c) {
        modify_command(c, std::type_index(typeid(c)));
    }
};

template<typename Der, typename SpecC> struct Modifier {
    static void execute(Der &d, Command &c) {
        d.modify_command(static_cast<SpecC &>(c)); 
    }
};

struct Derived: Base {
    using Base::modify_command; // <- Because there are overloads
    virtual void modify_command(SpecificCommandB &);
        // Put here the specific code you want for SpecificCommandB.
        // Note that this can be overriden in derived classes

    void modify_command(Command &c, std::type_index ti) override {
        using callable = void (*)(Derived &, Command &);
        const static std::unordered_map<std::type_index, callable> derived_map =
        {
            { std::type_index(typeid(SpecificCommandB)), Modifier<Derived, SpecificCommandB>::execute }
        };
        auto find_result = derived_map.find(ti);
        if(derived_map.end() == find_result) { Base::modify_command(c, ti); }
        else { (*find_result->second)(*this, 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{});
}