简体   繁体   English

我应该在这里使用 dynamic_cast 吗?

[英]Should i use dynamic_cast here?

Well, i have next code:好吧,我有下一个代码:

#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()
{

}

The question is - how can i work only with base_1 and base_2 interfaces?问题是 - 我怎样才能只使用 base_1 和 base_2 接口? Should i create two separate listeners for them, and send two events in create() function, or should i use dynamic_cast for downcasting and send only one event in create() function?我应该为它们创建两个单独的侦听器,并在 create() function 中发送两个事件,还是应该使用 dynamic_cast 进行向下转换并在 create() function 中只发送一个事件? Is this good code design or is this feels like code smell?这是好的代码设计还是感觉像代码气味?

UPD:升级版:

For example: base_1 - is render_base class, which contains render data, and have functions for set and get this data base_2 - collider base class which contains collider data, and have functions for set and get this data base_3 is physic base class and object is inheritance of all this classes. For example: base_1 - is render_base class, which contains render data, and have functions for set and get this data base_2 - collider base class which contains collider data, and have functions for set and get this data base_3 is physic base class and object is所有这些类的 inheritance。 And when i want work only with render class i use create event which send only render_base class to the render_system, which works only with renders objects and truly use polymorphism.当我只想使用渲染 class 时,我使用创建事件,该事件仅将 render_base class 发送到 render_system,它仅适用于渲染对象并真正使用多态性。 But if i want in some other place work with collider and physic objects, without knowledge about render - how can i use polymorphism here in base classes?但是,如果我想在其他地方使用对撞机和物理对象,而不了解渲染 - 我如何在基类中使用多态性?

It is hard to tell what design you should choose as this heavily depends on the overall structure of the application.很难说应该选择哪种设计,因为这在很大程度上取决于应用程序的整体结构。

Generally, I would avoid having a function with the signature virtual void object_created( base_main* o ) in which you dynamically cast to base_* and work on that directly in this function.通常,我会避免使用带有签名virtual void object_created( base_main* o )的 function,在其中您可以动态转换为base_*并直接在此 function 中进行处理。 Because the function signature is part of the documentation of the API.因为 function 签名是 API 文档的一部分。

So I would create distinct functions for base_1 and base_2 and call those.所以我会为base_1base_2创建不同的函数并调用它们。

How to do that depends again on the overall structure.如何做到这一点再次取决于整体结构。 You could create a helper function, that forwards the call to the other functions (this is just a fast implementation how that could look like:您可以创建一个帮助程序 function,它将调用转发给其他函数(这只是一个快速实现,可能看起来像:

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);
  }
}

And then you could use it like this:然后你可以像这样使用它:

#include <iostream>
#include <vector>

class base_main {
public:
  virtual ~base_main() {}
};

class base_1 : virtual public base_main {};

class base_2 : virtual public base_main {};

class base_3 : virtual public base_main {};

class object : public base_1, public base_2, public base_3 {};

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);
  }
}

struct listener_base {
  virtual void object_created(base_main *o) = 0;
};

struct specific_listener : public listener_base {
  void object_created(base_main *o) override {
    forward_if<base_1 *>(o, this, &specific_listener::object_created);
    forward_if<base_2 *>(o, this, &specific_listener::object_created);
  }

  void object_created(base_1 *o) {
    std::cout << "object created base_1" << std::endl;
  }

  void object_created(base_2 *o) {
    std::cout << "object created base_2" << std::endl;
  }
};

int main() {
  std::vector<listener_base *> listeners;
  listeners.push_back(new specific_listener());
  object o;

  for (auto listener : listeners) {
    listener->object_created(&o);
  }

  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM