从已知基类的未知派生类初始化对象



所以,我正在为一个小D2D引擎制作一个库;但这不是重点,问题是,我有这个类,它将是用户的类将继承的基类。我的主要想法是这样的:

struct BaseEngine {
// I have two pure virtual functions so the user has to define them.
virtual bool onLoad() = 0;
virtual bool onFrame() = 0;
};

现在,如果所有这些都在同一个项目中,我可以在那之后做这样的事情:

struct Derived : public BaseEngine {
bool onLoad() override;
bool onFrame() override;
};
const std::unique_ptr<BaseEngine> app = std::make_unique<Derived>();

但事实上,我的想法是,不要在头文件中保存派生类,并且在没有任何派生类定义的情况下构建库,因此,用户可以在项目中随意命名。

当然,它不允许我编译它,因为我不能构造BaseEngine,因为它有纯虚拟函数。

然后我想以某种方式使用模板来解决这个问题?现在我对模板不是很熟悉,但我的想法是制作一些类似的东西:

std::unique_ptr<BaseEngine> app;
template<class T : public BaseEngine>
void instantiator() {
app = std::make_unique<T>();
}

知道CCD_ 2持有CCD_ 3和CCD_。当然,当我需要一个特性,比如显式派生类的模板时,就不存在任何特性(至少我不知道(。

我的主要问题是:有没有一种方法可以让我从已知基类的"未知"派生类初始化对象

编辑:忘记提到主函数(在本例中为WinMain(将在引擎端,因为它负责窗口类注册和所有那些讨厌的消息

听起来你想把你的代码编译成一个共享库,你可以在另一个项目中链接到它,它将成为主要的可执行文件。不幸的是,由于编译方式的差异,库和可执行文件之间共享类类型可能会出现问题——我不建议采用这种方法。

不过,如果你可以一次编译所有文件(即用户可以访问未编译的源文件和头文件(,你就不必处理这个问题了。只需提供一个使用BaseEngine实例的函数。

// BaseEngine.h
class BaseEngine { /* ... */ }
void startGame(std::unique_ptr<BaseEngine> engine) { /* ... */ }
// main.cpp (user edits this file)
#include "BaseEngine.h"
class DerivedEngine : public BaseEngine {
// override methods here
}
int main() {
return startGame(std::make_unique<DerivedEngine>());
}

通常的答案是在引擎中使用一个函数,该函数将调用方创建的BaseEngine派生对象作为参数。

// Engine side function
bool InitializeEngine(BaseEngine * pEngine);

另一种答案(取决于用户提供的代码的捆绑方式(是使用一个集合名称导出函数,并让该函数返回一个创建的BaseEngine派生对象。

// User side code
BaseEngine * CreateEngine();

然后使用dlopen/dlsym(或windows上的LoadLibrary/GetProcAddress(获取CreateEngine的函数指针。在任何一种情况下,都是已知对象类型的用户代码负责创建对象。

静态多态性:奇怪的递归模板模式(CRTP(

您可能需要考虑使用奇怪重复模板模式(CRTP(:

#include <ios>
#include <iostream>
#include <memory>
#include <type_traits>
template <class T> struct BaseEngine {
bool onLoad() const { return static_cast<T const *>(this)->onLoad(); }
bool onFrame() { return static_cast<T *>(this)->onLoad(); }
};
// API exposed to library users.
template <typename T,
typename = std::enable_if_t<std::is_base_of<BaseEngine<T>, T>::value>>
auto createEngine() {
return std::make_unique<T>();
}
template <typename T> bool foo(const BaseEngine<T> &engine) {
return engine.onLoad();
}
// Stub for your own testing etc.
struct StubEngine : BaseEngine<StubEngine> {
bool onLoad() const {
std::cout << "stub onLoad()n";
return true;
}
bool onFrame() {
std::cout << "stub onFrame()n";
return false;
}
};
struct BadEngine {};
int main() {
auto engine = createEngine<StubEngine>();
// auto bad_engine = createEngine<BadEngine>();
// error: no matching function for call to 'createEngine'
const bool f = foo(*engine);      // stub onLoad()
std::cout << std::boolalpha << f; // true
return 0;
}

通过使用模板实现静态多态性,您可以在库中使用BaseEngine上下文中的类型模板参数T,而不必知道T是什么(因为它将由库用户来实现特定的具体"静态派生"类,即特定的T(;然而,可能使用类型性状和SFINAE对T进行限制。

最新更新