Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多态DLL导出_C++_Winapi_Interface_Polymorphism_Dllexport - Fatal编程技术网

C++ 多态DLL导出

C++ 多态DLL导出,c++,winapi,interface,polymorphism,dllexport,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 --

我目前正在处理一个使用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)
{
  // ...
}
但是,现在应用程序发现类taskinpl中的默认实现还不够,因此在其自身范围内定义了一个新的派生类,如下所示:

--- AppImpl.h ---
#include "TaskInterface.h"

class AppImpl : public Task
{
  int func1(void) = { /* new stuff */ }
  int func2(void) = { /* new stuff */ }
};
然后在application.cpp中定义:

--- TheApplication.cpp ---

#include "AppImpl.h"
ApplImp * aNewTask = static_cast<Task*>(newTask());

aNewTask->func1();
aNewTask->func2();
您认为func1和func2在什么上下文中被调用?更正:它仍然是DLL类TaskImpl中的具体实现,而不是类AppImpl定义的派生

基本上这就是我的问题:我想在DLL中使用默认实现,但我想在应用程序端扩展它,所以除非我显式重写了ApplImp.h中的函数,否则我会回到DLL中taskinpl中定义的函数

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

我已经尝试过导出TaskInterface.h和Task.h,然后让ApplImp.h在DLL中包含具体类,但是编译不喜欢这样,原因很明显=>无法导出两次newTask

感谢您的帮助

由于您无论如何都需要通过DLL进行分配和解除分配,我建议在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
};

您也可以让任务包装器从任务派生.< /p> 如果我正确地理解了这个问题,您希望Apple从TASKIMP中派生出来,并根据需要调用TaskIMPL成员实现,使用标准的C++语法… 您不能直接这样做,因为应用程序和DLL是单独链接的,彼此之间没有编译时知识。应用程序在编译时不知道TaskImpl,因此编译器无法从中派生,也无法创建一个Vtable,该Vtable可能是来自应用程序和DLL的函数的组合

您可以选择组合对象,即在ApplImp内创建TaskImp实例,并将所有功能委托给ApplImp内的TaskImp实例。这在很多情况下是不方便的

一种更方便的方法是从DLL导出TaskImpl的实现:将整个类声明为u dllexport。不幸的是,这是最不可移植的方法,在一个大型项目中,它可能会导致一个巨大的dll导出部分,其中有10000个C++名称的条目被损坏。但您可能可以在其他DLL或应用程序中使用TaskImpl作为基类

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

ApplImp*aNewTask=静态任务


@dyp是的,为了简洁,我省略了。虽然它可能并不漂亮,但另一种选择是将所有必要的派生类与DLL一起提供,这意味着a每次应用程序需要更新,所以需要DLL,b DLL承载了大量无用的特定于应用程序的权重,当它应该定义一个轻量级接口,可以在用户空闲时进行扩展时。这只是未定义的行为,但我必须查看MSVC编译器对这种情况的说明。如果动态类型=实际创建的对象的类型不是要强制转换到的类型的基类,则不应将基类指针强制转换为派生类指针。
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
};