多态DLL出口

Polymorphic DLL exports

本文关键字:出口 DLL 多态      更新时间:2023-10-16

我当前正在处理一个使用DLL和使用DLL的应用程序的项目。像往常

---- TaskInterface.h ----
class Task {
public:
    virtual int func1(void) = 0;
    virtual int func2(void) = 0;
};
extern "C" __declspec(dllexport) Task * APIENTRY newTask();
--- Task.h ---
class TaskImpl : public Task
{
public:
    virtual int func1(void);
    virtual int func2(void):
};
Task * APIENTRY newTask()
{
    return static_cast<Task*>( new TaskImpl );
}
--- Task.cpp ---
int TaskImpl::func1(void)
{
 // ...
} 
int TaskImpl::func2(void)
{
  // ...
}

这在预期的情况下起作用,应用程序包括" AbstractTask.h",然后调用由类TaskImpl定义的相应函数:

--- TheApplication.cpp ---
Task aTask = newTask();
aTask->func1();
aTask->func2();
// ...

但是,现在该应用程序发现类TaskImpl中的默认实现不够,因此在其自己的范围内定义了一个新的派生类,例如:

--- AppImpl.h ---
#include "TaskInterface.h"
class AppImpl : public Task
{
  int func1(void) = { /* new stuff */ }
  int func2(void) = { /* new stuff */ }
};

然后在theapplication.cpp中定义:

--- TheApplication.cpp ---
#include "AppImpl.h"
ApplImp * aNewTask = static_cast<Task*>(newTask());
aNewTask->func1();
aNewTask->func2();

您认为func1()和func2()被调用?正确:它仍然是DLL类TaskImpl内部的具体实现,而不是Class Appimpl定义的派生。

基本上这是我的问题:我想从DLL内部使用默认实现,但是我希望能够在应用程序端将其扩展,因此,除非我明确地超过了Applimp.h中的功能,否则回到dll内部定义的一个。

这可能吗?如果是这样,我在做什么错?如果没有,我该如何完成同等的事情?

我已经在导出" taskInterface.h"answers" task.h",然后让Applimp.h在DLL中包含混凝土类,但是由于明显的原因,该编译不喜欢它=>无法导出NewTask()两次。

任何帮助都将受到赞赏!

您需要通过dll分配和Deallocation ,我建议您与DLL一起提供包装类。然后,该包装类可以设计为继承。

class Task {
public:
    virtual int func1(void) = 0;
    virtual int func2(void) = 0;
};
//                       v~~~~v probably dllimport in the header you ship
extern "C" __declspec(dllexport) Task * APIENTRY newTask();
class TaskWrapper {
public:
    TaskWrapper() : m_ptr( newTask() ) {}
    virtual ~TaskWrapper() { deleteTask(m_ptr); }
    virtual int func1(void) { m_ptr->func1(); }
    virtual int func2(void) { m_ptr->func2(); }
protected: // implementation omitted for brevity
    TaskWrapper(TaskWrapper const&);
    TaskWrapper(TaskWrapper&&);
    TaskWrapper& operator= (TaskWrapper const&);
    TaskWrapper& operator= (TaskWrapper&&);
private:
    Task* m_ptr; // preferably a unique_ptr
};

您也可以让TaskWrapper衍生自Task

如果我正确理解了问题,请使用标准C 语法来访问tastimp,并根据需要致电Taskimpl成员实现。

您不能直接这样做,因为应用程序和DLL分别链接并且没有彼此的编译时间知识。该应用程序在编译时不知道TaskImpl,因此编译器不能从中衍生出来,也无法创建可能是来自应用程序和DLL的Funcitons组合的VTable。

您可以组成对象,即在Applimp中创建一个TaskIMP的实例,并将所有函数委派给Applimp内部的Taskimp实例。在许多情况下,这是不方便的。

一种更方便的方法是从DLL中导出TaskImpl的实现:将整个班级声明为__DLLEXPORT。不幸的是,这是达到最低的方法,在一个大型项目中,它可能会导致巨大的DLL导出部分,其中10000 C - 名称 - 刻录条目。但是您也许可以将taskimpl用作其他DLL或应用程序中的基类。

btw,这不会编译,因为applimp是从任务派生的,而任务*不能隐式地施放到applimpl。

applimp * anewtask = static_cast(newtask());