加载外部 class c++
Loading external class c++
我正在尝试加载在 .dll 文件中定义的 class。但是,在 dll 中定义 class 有两种稍微不同的方法。我不确定哪种方法更合法,我也不知道为什么第二种方法也有效。这是一个简单的例子:
方法一:
在 main.cpp
:
#include <iostream>
#include <windows.h>
#include <memory>
#include "bar.h"
using namespace std;
typedef bar* (* MYDLLPROC)();
int main()
{
unique_ptr<bar> theresult;
auto thelib = LoadLibrary(TEXT("foo.dll"));
if (thelib != NULL) {
MYDLLPROC theprocs = (MYDLLPROC)GetProcAddress(thelib, "Myfoo");
cout << "load successfully" << endl;
theresult.reset(theprocs());
theresult->printmsg();
} else {
cout << "cannot load the dll" << endl;
}
return 1;
}
bar
在bar.h
中定义为纯虚class:
class bar {
public:
virtual ~bar() {};
virtual void printmsg() = 0;
};
在foo.dll
源文件中:
#include <iostream>
#include <windows.h>
#include "bar.h"
using namespace std;
class foo: public bar {
public:
foo() { cout << "foo is instantiated" << endl; }
~foo() {}
void printmsg() final { cout << "msg from foo print" << endl; }
};
extern "C" __declspec(dllexport) foo* __cdecl Myfoo()
{
return new foo();
}
在第一种方法中,纯虚拟 class bar
被用作接口,并且它的成员函数被 foo
中的成员函数覆盖是有意义的dll 已加载。
然而,我发现 foo
不必从 bar
派生,只要 foo
有一个 Vtable,一切仍然有效:
第二种方法,除了foo
的定义外,其他都是一样的:
#include <iostream>
#include <windows.h>
using namespace std;
class foo {
public:
foo() { cout << "foo is instantiated" << endl; }
virtual ~foo() {}
virtual void printmsg() final { cout << "msg from foo print" << endl; }
};
extern "C" __declspec(dllexport) foo* __cdecl Myfoo()
{
return new foo();
}
谁能告诉我为什么第二种方法有效?我有点困惑,因为 foo
和 bar
没有关系,但是 bar
中的成员函数仍然可以被覆盖。
第一个示例非常脆弱,因为它隐含地依赖于 foo
和 bar
指针可互换。
第二个示例已损坏,因为函数 Myfoo
returns 指向 class foo
的指针与 bar
无关,取消引用它会导致未定义的行为.
函数签名必须与 dll 中实现的函数匹配。您现在拥有的基本上是从 foo *
到 bar *
的 reinterpret_cast
。
因此,您将返回 foo*
的函数转换为返回 bar*
的函数,然后调用它。
最终结果是您有一个指向 foo
的指针,它是一个指向不相关类型 bar
的指针。以任何方式使用它都会导致 undefined behavior.
它似乎在这种特定情况下有效,因为 printmsg
虚函数在两个 vtable 中的位置相同,因此在 foo
的实例上调用 bar::printmsg
只需调用“vtable 中的第 N 个条目”。如果您在 printmsg
之前将另一个虚拟成员添加到 foo
,那么它可能会被调用(或者程序可能会崩溃)。
我正在尝试加载在 .dll 文件中定义的 class。但是,在 dll 中定义 class 有两种稍微不同的方法。我不确定哪种方法更合法,我也不知道为什么第二种方法也有效。这是一个简单的例子:
方法一:
在 main.cpp
:
#include <iostream>
#include <windows.h>
#include <memory>
#include "bar.h"
using namespace std;
typedef bar* (* MYDLLPROC)();
int main()
{
unique_ptr<bar> theresult;
auto thelib = LoadLibrary(TEXT("foo.dll"));
if (thelib != NULL) {
MYDLLPROC theprocs = (MYDLLPROC)GetProcAddress(thelib, "Myfoo");
cout << "load successfully" << endl;
theresult.reset(theprocs());
theresult->printmsg();
} else {
cout << "cannot load the dll" << endl;
}
return 1;
}
bar
在bar.h
中定义为纯虚class:
class bar {
public:
virtual ~bar() {};
virtual void printmsg() = 0;
};
在foo.dll
源文件中:
#include <iostream>
#include <windows.h>
#include "bar.h"
using namespace std;
class foo: public bar {
public:
foo() { cout << "foo is instantiated" << endl; }
~foo() {}
void printmsg() final { cout << "msg from foo print" << endl; }
};
extern "C" __declspec(dllexport) foo* __cdecl Myfoo()
{
return new foo();
}
在第一种方法中,纯虚拟 class bar
被用作接口,并且它的成员函数被 foo
中的成员函数覆盖是有意义的dll 已加载。
然而,我发现 foo
不必从 bar
派生,只要 foo
有一个 Vtable,一切仍然有效:
第二种方法,除了foo
的定义外,其他都是一样的:
#include <iostream>
#include <windows.h>
using namespace std;
class foo {
public:
foo() { cout << "foo is instantiated" << endl; }
virtual ~foo() {}
virtual void printmsg() final { cout << "msg from foo print" << endl; }
};
extern "C" __declspec(dllexport) foo* __cdecl Myfoo()
{
return new foo();
}
谁能告诉我为什么第二种方法有效?我有点困惑,因为 foo
和 bar
没有关系,但是 bar
中的成员函数仍然可以被覆盖。
第一个示例非常脆弱,因为它隐含地依赖于 foo
和 bar
指针可互换。
第二个示例已损坏,因为函数 Myfoo
returns 指向 class foo
的指针与 bar
无关,取消引用它会导致未定义的行为.
函数签名必须与 dll 中实现的函数匹配。您现在拥有的基本上是从 foo *
到 bar *
的 reinterpret_cast
。
因此,您将返回 foo*
的函数转换为返回 bar*
的函数,然后调用它。
最终结果是您有一个指向 foo
的指针,它是一个指向不相关类型 bar
的指针。以任何方式使用它都会导致 undefined behavior.
它似乎在这种特定情况下有效,因为 printmsg
虚函数在两个 vtable 中的位置相同,因此在 foo
的实例上调用 bar::printmsg
只需调用“vtable 中的第 N 个条目”。如果您在 printmsg
之前将另一个虚拟成员添加到 foo
,那么它可能会被调用(或者程序可能会崩溃)。