简体   繁体   中英

Loading external class c++

I am trying to load a class defined in a.dll file. However there are two slightly different ways of defining the class in the dll. I'm not sure which is the more legit way to do it, and I don't know why the second way also works. Here is a simple example:

Method 1: In 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;
}

The bar is defined as a pure virtual class in bar.h :

class bar {
public:
    virtual ~bar() {};
    virtual void printmsg() = 0;
};

In the foo.dll source file:

#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();
}

In the first method the pure virtual class bar is used as an interface, and it makes sense that its member function(s) is overridden by that in foo when the dll is loaded.

However, I found that foo doesn't have to be derived from bar , everything still works as long as foo has a Vtable:

In the second method, everything is the same except for the definition of 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();
}

Could anyone please let me know why the second method works? I'm a bit confused because foo and bar are not related but the member function in bar can still be overridden.

So you cast a function returning foo* as a function returning bar* and then invoking it.

The end result is that you have a pointer to foo which is a pointer to an unrelated type bar . Using it in any way will lead to undefined behavior .

It appears to work in this specific case because the position of the printmsg virtual function in both vtables is the same, so invoking bar::printmsg on an instance of foo simply calls the "Nth entry in the vtable". If you add another virtual member to foo before printmsg , then it might get called instead (or the program might crash).

First example is very fragile because it implicitly relies on foo and bar being pointer-interchangeble.

Second example is broken because function Myfoo returns a pointer to class foo that is not related to bar and dereferencing it causes undefined behavior.

Function signature must match the function implemented in the dll. What you have right now is basically a wild reinterpret_cast from foo * to bar * .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM