从另一个动态库分配未知的继承类

问题描述 投票:0回答:1

我正在开发一个小型游戏引擎项目,我想制作一个实体分配系统。

想法是这样的:引擎DLL是“不可更改的”,由我提供。 开发人员将能够使用自定义实体类型自行编译游戏 DLL。

每个实体都派生自引擎的

CBase
类。实体具有类名称,在读取地图时将使用这些名称。实体将使用这些类名“生成”。它基本上是该实体的别名。

但是有一个问题:

“生成”实体的分配应在引擎中完成。引擎应该能够调用基本函数,而不能调用附加函数。

但是引擎不会从游戏DLL中导入这些类,所以我不能只使用

new EntityClass

如何从其他 DLL 分配未知类(从已知类派生)?有没有办法通过函数“传递类型”?


我之前的解决方法就像这样的伪代码:

发动机:

class DLLEXPORT CBase
{
  std::string className;

  virtual void Init();
  virtual void OtherMethod();
}

CBase* CreateNewEntity(const char* classname)
{
  CBase* newentity = static_cast<CBase*>(SERVER_DLL_GETNEWOBJECT(classname));
  newentity->Init();
  entitylist.addentity(newentity);
}

游戏DLL:

class DLLEXPORT CBaseEntity : public DLLIMPORT CBase
{
  //Called by engine
  virtual void Init() override;
  virtual void OtherFunction() override;

  //Inaccesible by engine
  virtual void AnotherFunction() override;
}

CBaseEntity* SERVER_DLL_GETNEWOBJECT(const char* classname)
{
  if (strcmp(className, "Entity_Weapon_Test") == 0)
  {
      return static_cast<CBaseEntity*>(new CTestWeapon);
  }
  else
      return nullptr;
}

SERVER_DLL_GETNEWOBJECT 从 Game DLL 中导出,并导入到 Server DLL 中。这将是一个预定义的函数。

但在此解决方法中,分配是由游戏 DLL 完成的,而不是由引擎完成的。所以我不能用它。

c++ oop dll game-engine game-development
1个回答
0
投票

我期待这样的事情:

#include <memory>
#include <string>
#include <functional>
#include <map>
#include <stdexcept>
#include <iostream>

// Declare an "interface" (abstract baseclass)
// this is the only knowledge your engine
// and client code will share
//
// But make sure client code compiles with an ABI
// compatible compiler!
//
class EntityItf
{
public:
    virtual ~EntityItf() = default;
    virtual void DoSomething() = 0;
};

using creation_function_t = std::function<std::unique_ptr<EntityItf>()>;

class /*dllexport */ EntityFactory
{
public:
    // Meyers singleton
    inline static EntityFactory& Instance()
    {
        static EntityFactory factory;
        return factory;
    }

    void RegisterCreationMethod(const std::string& entity_name, creation_function_t creation_function)
    {
        if ( m_factory_functions.find(entity_name) != m_factory_functions.end())
        {
            throw std::runtime_error{"An entity with that name has already been registered"};
        }

        m_factory_functions[entity_name] = creation_function;
    }

    std::unique_ptr<EntityItf> CreateEntity(const std::string& entity_name)
    {
        if ( m_factory_functions.find(entity_name) == m_factory_functions.end())
        {
            throw std::runtime_error{"Unknown entity name"};
        }

        return m_factory_functions[entity_name]();
    }

private:
    EntityFactory() = default;
    ~EntityFactory() = default;

    std::map<std::string,creation_function_t> m_factory_functions;
};

// Developer code

class MyEntity :
    public EntityItf
{
public:
    void DoSomething() override
    {
        std::cout << "Hello World!\n";
    }
};

int main()
{
    auto& factory = EntityFactory::Instance();
    factory.RegisterCreationMethod("MyEntity", []{ return std::make_unique<MyEntity>(); });

    auto my_entity = factory.CreateEntity("MyEntity");
    my_entity->DoSomething();

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.