我目前正在开发一个使用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()两次。
感谢任何帮助!
答案 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());