【发布时间】:2021-05-21 15:49:30
【问题描述】:
我正在尝试加载在 .dll 文件中定义的类。然而,在 dll 中定义类有两种略有不同的方法。我不确定哪种方法更合法,我也不知道为什么第二种方法也有效。这是一个简单的例子:
方法一:
在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 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();
}
在第一种方法中,纯虚类bar 用作接口,它的成员函数在加载dll 时被foo 中的成员函数覆盖。
但是,我发现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 中的成员函数仍然可以被覆盖。
【问题讨论】:
-
第二个是在你的测试程序中导致的未定义行为。不幸的是,有时未定义的行为似乎有效。
-
@drescherjm 哦,抱歉,这是一个错字,我已更正为 Myfoo。感谢您指出这一点!
-
@drescherjm 这是否意味着虽然第二种方法有效但有时会出错?
-
这是否意味着虽然第二种方法有效但有时会出错? 是的,我相信是的。在第二个 dll 中,
foo类不是bar,但通过强制转换typedef bar* (* MYDLLPROC)();你是在对编译器撒谎,告诉它“相信我返回的指针是指向条形的指针” -
@drescherjm 有道理!非常感谢!
标签: c++ c dll vtable loadlibrary