【问题标题】:Design test with templates and inheritance使用模板和继承进行设计测试
【发布时间】:2014-06-23 09:42:49
【问题描述】:

我有一个关于 C++ 设计的问题。 正如您在下面的代码中看到的那样,存在设计问题。我希望能够拥有一个TestClass,它继承自从ModeBase 派生的零个或多个类(在此示例中为ModeOneModeTwo)。如果TestClass继承自ModeOne,它就可以使用MethodeOne(),而TestClass需要实现MethodOne(),这就是我想要的。

class ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeBase() = default;
};

class ModeOne : private ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeOne() = default;

    virtual void MethodOne() {}
};

class ModeTwo : private ModeBase
{
//--Methods--------------------------------------------------------------------
public:
    virtual ~ModeTwo() = default;

    virtual void MethodTwo() {}
};



class TestBase
{
//--Methods--------------------------------------------------------------------
public:
    TestBase() : currentMode_( nullptr ) {}

    virtual ~TestBase() = default;

    template <class Mode, class T>
    void ChangeMode()
    {
        if( std::is_base_of<Mode, T>::value )
        {
            // Class does inherit from Mode so we make sure the current mode
            // has changed
            currentMode_ = std::make_shared<Mode>();
        }
        else
        {
            // Class does not inherit from Mode so we don't do anything
        }
    }

    template <class Mode>
    bool CurrentMode()
    {
        if( std::dynamic_pointer_cast<Mode>(currentMode_) != nullptr )
        {
            return true;
        }
        return false;
    }

//--Data members---------------------------------------------------------------
private:
    std::shared_ptr<ModeBase> currentMode_;
};

class TestOne
    : public TestBase
    , private ModeOne
    , private ModeTwo
{
//--Methods--------------------------------------------------------------------
    ~TestOne() = default;

    void HeartbeatTick()
    {
        if( CurrentMode<ModeOne>() )
        {
            MethodOne();
        }
        else if( CurrentMode<ModeTwo>() )
        {
            MethodTwo();
        }
    }

    virtual void MethodOne() {}
    virtual void MethodTwo() {}
};


class SomeManager
{
    ~SomeManager() = default;

    void ChangeAllMode()
    {
        for( auto it = vector_.begin(); it != vector_.end(); ++it )
        {
            // Here is the problem with this implementation. I need to know
            // the type of the TestBase derived class (TestOne) to use it as
            // a `ChangeMode` method template parameter.
            //(*it)->ChangeMode<AIModeFollowLine, SOMETYPE>();
        }
    };

    std::vector<std::shared_ptr<TestBase>> vector_;
};

我已经知道这是一个糟糕的设计,因为 vector_ 将在运行时填充,所以我无法像这样使用 ChangeMode。使用多方法似乎是一个很好的解决方案,不是吗?如果是这样,设计会是什么样子?

【问题讨论】:

    标签: c++ templates multiple-inheritance


    【解决方案1】:

    Multimethods(AKA 多重分派)处理基于所涉及参数的运行时类型将调用分派到单个函数的问题。这似乎不是您的问题(或者我误解了您?),因为您有两个不同的方法名称,在两种不同的类型上实现。

    您的目标似乎是根据您注入到类中的运行时类型来选择方法实现。目前尚不清楚您是否能够规定注入采用的形式,但如果可以,那么为什么不直接注入实现呢?然后您可以使用 隐式接口 而不是显式接口。换句话说,为什么不注入functor-like 对象呢?

    class TestBase
    {
    public:
        typedef std::function<void ()> Ticker;
    
        TestBase(Ticker hbTicker) : ticker{hbTicker} {}
    
        void HeartbeatTick() {
           ticker();
        }
    
        void setTicker(Ticker hbTicker){
            ticker = hbTicker;
        }
    
    private:
        Ticker ticker;
    };
    

    如果满足您的要求,对我来说似乎不那么复杂。

    如果您确实需要实现多重分派,您可能需要在每个需要确定其运行时类型的参数上实现visitor 模式。不确定这是否适用于多个参数(至少我自己没有尝试过多个参数)。或者你可以使用RTTI 和一个案例陈述或类似的东西。

    【讨论】:

    • 感谢您的回答。但我也想根据SomeManager::ChangeAllMode 注入的类型更改运行时的代码。当注入发生时,如果TestOne 派生自注入类型(ModeOneModeTwo),那么我们可以设置代码。
    • 但是TestBase 不知道派生类TestOne 是否派生自这些类型...
    • @Athanase 有什么问题?如果您想在 all 您的类中全局使用相同的功能,则让管理器将所有功能对象设置为新功能。或者使用全局指针并将其注入所需的对象,然后更改该指针指向的内容。据我所知,您的解决方案没有理由如此复杂。
    【解决方案2】:

    我只是在这里愚蠢! 我只需要使用不同的ChangeMode() 方法才能知道TestBase 是否属于TestOne 类型ModeBase

    template<typename Mode>
    bool
    IsSame( TestBase* base )
    {
         return dynamic_cast<Mode*>(base) != nullptr;
    };
    
    template <class Mode>
    void
    ChangeMode()
    {
        if( isSame<Mode>(this) )
        {
            // Change the ticker method
        }
        else
        {
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 2019-09-29
      • 2015-04-18
      相关资源
      最近更新 更多