多态DLL导出

时间:2014-02-07 15:54:24

标签: c++ winapi interface polymorphism dllexport

我目前正在开发一个使用DLL和使用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中的具体实现,而不是类AppImpl定义的派生。

基本上这是我的问题:我想在DLL中使用默认实现,但我希望能够在Application端扩展它,所以除非我已经在ApplImp.h中显式覆盖了一个函数,回退到DLL中的TaskImpl中定义的那个。

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

我已经玩过导出“TaskInterface.h”和“Task.h”然后让ApplImp.h包含DLL中的具体类,但是由于显而易见的原因,编译不喜欢这种情况=&gt;无法导出newTask()两次。

感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

由于你需要通过DLL分配和deallocate ,我建议在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

答案 1 :(得分:0)

如果我正确理解了这个问题,你希望ApplImp从TaskImp派生,并根据需要使用标准C ++语法调用TaskImpl成员实现。

您无法直接执行此操作,因为应用程序和DLL是分开链接的,并且彼此之间没有编译时的知识。应用程序在编译时不了解TaskImpl,因此编译器无法从中派生,也无法创建可能是应用程序和DLL的函数组合的Vtable。

您可以组合对象,即在ApplImp中创建TaskImp的实例,并将所有函数委托给ApplImp中的TaskImp实例。在许多情况下这很不方便。

更方便的方法是从DLL导出TaskImpl的实现:将整个类声明为__dllexport。不幸的是,这是最便携的方式,在大型项目中,它可能会导致一个巨大的dll导出部分,其中包含10000个C ++ - 名称错误的条目。但是您可以将TaskImpl用作其他DLL或应用程序中的基类。

顺便说一下,这不会编译,因为ApplImp是从Task派生的,而且Task *不能隐式地转换为ApplImpl。

  

ApplImp * aNewTask = static_cast(newTask());

相关问题