我应该在这里使用 dynamic_cast 吗?

时间:2021-01-26 12:50:41

标签: c++ oop design-patterns

好吧,我有下一个代码:

#include <type_traits>
#include <iostream>
#include <string>
#include <list>
#include <functional>

class base_main
{
public:
    virtual ~base_main()
    {
    }
    // some methods
};

class base_1 : virtual public base_main
{
    // some methods
};

class base_2 : virtual public base_main
{
    // some methods
};

class base_3 : virtual public base_main
{
    // some methods
};

class object : public base_1, public base_2, public base_3
{
    // some methods
};

// in other *hpp file

class object_controller_listener
{
public:
    virtual void object_created( base_main* o )
    {
        // well, i want to work only with base_1 and base_2 interfaces, but not with base_3, and also i don't want to know something about object class in this *hpp
        // is it good code design?
        auto* xxx = dynamic_cast<base_1*>( o );
    }
};

class objects_controller
{
    void create()
    {
        std::unique_ptr<object> obj;

        // ...
        
        for( auto listener : m_listeners )
            listener->object_created( obj.get()  );
    }

    std::list<object_controller_listener*> m_listeners;
};

int main()
{

}

问题是 - 我如何只使用 base_1 和 base_2 接口?我应该为它们创建两个单独的侦听器,并在 create() 函数中发送两个事件,还是应该使用 dynamic_cast 进行向下转换并在 create() 函数中仅发送一个事件?这是好的代码设计还是感觉像代码味道?

更新:

例如:base_1 - 是render_base 类,包含渲染数据,并具有设置和获取此数据库的功能 base_2 - 碰撞器基类,其中包含对撞机数据,并具有设置和获取此数据库的功能 base_3 是物理基类object 是所有这些类的继承。当我只想使用渲染类时,我使用 create 事件,该事件仅将 render_base 类发送到 render_system,它仅适用于渲染对象并真正使用多态性。但是,如果我想在不了解渲染的情况下在其他地方使用对撞机和物理对象 - 我如何在基类中使用多态?

1 个答案:

答案 0 :(得分:2)

很难说您应该选择哪种设计,因为这在很大程度上取决于应用程序的整体结构。

通常,我会避免使用签名为 Promise 的函数,您可以在其中动态转换为 virtual void object_created( base_main* o ) 并直接在此函数中处理该函数。因为函数签名是 API 文档的一部分。

所以我会为 base_*base_1 创建不同的函数并调用它们。

如何做到这一点再次取决于整体结构。您可以创建一个辅助函数,将调用转发到其他函数(这只是一个快速实现,看起来像:

base_2

然后你可以像这样使用它:

template <typename DestT, typename SrcT, typename T>
void forward_if(SrcT obj, T *o, void (T::*f)(DestT)) noexcept {
  if (auto tmp = dynamic_cast<DestT>(obj); tmp != nullptr) {
    (o->*f)(tmp);
  }
}