c ++中的纯虚函数机制如何从DLL公开函数

时间:2017-07-12 20:04:25

标签: c++ dll

考虑下一个c ++代码片段

1。在EXE中:

Base.hpp

#ifndef _BASE_H_
#define _BASE_H_ 
class Base
{
    public:
    Base(){};
    virtual double Add(double &x, double &y) = 0; 

};
#endif

的main.cpp

#include <iostream>
#include "Base.hpp"
#include "DerivedFactory.hpp"
void main()
{
    Base *theBase = DerivedFactory::Create();
    double x = 4.9, y = 3.3,z;
    z = theBase->Add(x, y);//Works when Add is pure virtual function, but how??? 
                           //Linker error when Add is not pure virtual
}

2。在隐式链接的DLL中

Derived.hpp

#ifndef _DERIVED_H_
#define _DERIVED_H_
#include "Base.hpp"
class Derived : public Base
{
    public:
    double Add(double &x, double &y);
};
#endif

DerivedFactory.hpp

#ifndef _DERIVEDFACTORY_H_
#define _DERIVEDFACTORY_H_
#include "Derived.hpp"

class DerivedFactory
{
    public:
    __declspec(dllexport) static  Derived* Create();
};
#endif

Derived.cpp

#include "Derived.hpp"
 double Derived::Add(double &x, double &y)
{
    return x + y;
}

DerivedFactory.cpp

#include "DerivedFactory.hpp"
Derived* DerivedFactory::Create()
{
    Derived* theDerived = new Derived;
    return theDerived;
}
  1. 主要的问题是当exe中唯一导出的函数是Create()时,exe如何“知道”从dll中正确实现Add的实现?

  2. 当Add()“只是”虚拟而不是纯虚拟时,为什么会出现链接器错误?

2 个答案:

答案 0 :(得分:3)

  1. DLL将在其全局数据部分的某处包含Derived的vtable。在DLL中创建的Derived实例将其vtable指针分配给该地址。

  2. 如果Base的{​​{1}}声明不是纯虚拟的,您必须在声明之上提供它的定义。

  3. 修改:有关vtable的说明,请参阅以下答案: why do I need virtual table?

    从纯粹的风格角度来看,我还要提到在这种情况下,工厂通常会返回Add()类的实例,如下所示:

    DerivedFactory.hpp

    Base

    这样,#include "Base.hpp" class DerivedFactory { public: __declspec(dllexport) static Base* Create(); }; 的封装完全,整齐地保留在DLL中。

答案 1 :(得分:2)

Derived中的虚拟表是在创建实例时由DLL设置的,因此当通过Base指针调用的方法时,虚拟表已经在虚拟表中设置了正确的地址(EXE将使用Derived虚拟表)表来自DLL)。

请注意,EXE在链接时不会从DLL导入虚拟表,因为它不需要(它通过Base接口访问DLL在内存中的Derived的虚拟表)。因此,它不仅适用于隐式链接,而且还适用于在运行时加载DLL(LoadLibrary / GetProcAddress - 但为此工厂方法最好不是工厂类的一部分,而是独立的extern“C”导出函数)。

有关纯虚拟接口和DLL的更多详细信息,请参见此处:Providing SDK for my C++ Application