Why I cannot call public non-virtual member function of DLL?

T

thomas

Hi,

Hmm. seems a little silly..
Here comes the puzzle.
-----dll------------
class TestAdd
{
public:
void TestNormal();
virtual void TestVirtual();
}
extern "C" TestAdd* TestAddCreate(){
return new(std::nothrow) TestAdd();
}
------------------

Above is part of the dll class. The implementation part is missed
deliberately.
TestAdd* instance = TestAddCreate();
When I call "instance->TestNormal()", it says
------message-----
error LNK2019: unresolved external symbol "public: void __thiscall
TestAdd::TestNormal(void)" (?TestNormal@TestAdd@@QAEXXZ) referenced in
function _main
-----message-----

But "instance->TestVirtual()" works.

I didn't learn "only virtual method can be called outside the dll". Am
I missing something? Thanks.

Tom..
 
I

Ian Collins

Hi,

Hmm. seems a little silly..
Here comes the puzzle.
-----dll------------
class TestAdd
{
public:
void TestNormal();
virtual void TestVirtual();
}
extern "C" TestAdd* TestAddCreate(){
return new(std::nothrow) TestAdd();
}
------------------

Above is part of the dll class. The implementation part is missed
deliberately.
TestAdd* instance = TestAddCreate();
When I call "instance->TestNormal()", it says
------message-----
error LNK2019: unresolved external symbol "public: void __thiscall
TestAdd::TestNormal(void)" (?TestNormal@TestAdd@@QAEXXZ) referenced in
function _main
-----message-----

But "instance->TestVirtual()" works.

I didn't learn "only virtual method can be called outside the dll". Am
I missing something? Thanks.

Posting to a windows group maybe?
 
R

red floyd

Hi,

   Hmm. seems a little silly..
   Here comes the puzzle.
-----dll------------
class TestAdd
{
public:
      void TestNormal();
      virtual void TestVirtual();}

extern "C" TestAdd* TestAddCreate(){
      return new(std::nothrow) TestAdd();}

------------------

Above is part of the dll class. The implementation part is missed
deliberately.
TestAdd* instance = TestAddCreate();
When I call "instance->TestNormal()", it says
------message-----
error LNK2019: unresolved external symbol "public: void __thiscall
TestAdd::TestNormal(void)" (?TestNormal@TestAdd@@QAEXXZ) referenced in
function _main
-----message-----

Where's the *DEFINITION* of TestNormal()? This has absolutely nothing
to do with DLLs.

Please see FAQ 5.8. Post a minimal *COMPILEABLE* example that
exhibits
the behavior in question.
 
L

Lars Tetzlaff

Am 01.09.2010 10:30, schrieb thomas:
Hi,
....

But "instance->TestVirtual()" works.

I didn't learn "only virtual method can be called outside the dll". Am
I missing something? Thanks.

Tom..

You are missing __declspec(dllexport):

class __declspec(dllexport) TestAdd
{

As stated before, this is not a C++ question.

Lars
 
A

Andrey Tarasevich

thomas said:
But "instance->TestVirtual()" works.

I didn't learn "only virtual method can be called outside the dll". Am
I missing something? Thanks.

You failed to "export" your function from the DLL. This is outside the
scope of standard C++ language, so each implementation provides it own
means for "exporting" functions from DLL.

Virtual functions usually don't need to be exported, since in a typical
implementation it is called _indirectly_ - though a pointer stored in
virtual methods table. However, if you attempt to call your virtual
function directly (by using a qualified name)

instance->TestAdd::TestVirtual();

you will most likely run into the same problem with virtual function as
well.
 
B

BGB / cr88192

thomas said:
Hi,

Hmm. seems a little silly..
Here comes the puzzle.

I didn't learn "only virtual method can be called outside the dll". Am
I missing something? Thanks.

main issue:
the non-virtual method is not exported, so the code trying to call the
method can't see it.

basically, any non-virtual methods are handled as direct calls by the
compiler, and so need to be exported so that they can be seen from the other
side (virtual methods don't need to be seen, since they are referenced
indirectly via a vtable).

so, options:
make all methods virtual;
export all methods.


or, my preferred option:
don't use C++ APIs across DLL boundaries (IMO, in the larger sense, it
creates more problems than it is worth).

this means not only using C or 'extern "C" ' for exported API functions, but
also not directly passing/using any class instances (or, if one does, a
C-level API should be provided for this).

granted, this latter option may be a little more work for a C++ API, as
there is both DLL-side logic to marshall whatever the class does to a C API,
and also client-side logic to re-wrap the API in C++ classes (the wrapper is
entirely contained within the headers, and so any logic there will typically
be embedded directly into the clients).

however, if the least-effort option is desired, and one doesn't care about
the possibility of mixing compilers or of versioning issues (building the
main app and DLL at different times can break their ability to work
together, ...), then the simplest option is to make all methods virtual.

granted, yes, as you have done, it is generally needed to have the "new"
operator called from within the same DLL that created the class. similar
also goes for things like "delete", attempting to use RTTI, ... as otherwise
things can turn out badly...
 
L

Lars Tetzlaff

Am 02.09.2010 19:59, schrieb BGB / cr88192:
granted, yes, as you have done, it is generally needed to have the "new"
operator called from within the same DLL that created the class. similar
also goes for things like "delete", attempting to use RTTI, ... as otherwise
things can turn out badly...

Can you explain this? What should happen if you call new from outside
the dll?

Lars
 
B

BGB / cr88192

Lars Tetzlaff said:
Am 02.09.2010 19:59, schrieb BGB / cr88192:

Can you explain this? What should happen if you call new from outside
the dll?

unless the necessary internal symbols are also exported, the new operator
will not itself work (it will not be able to find the vtable for the class,
....).

however, even in the case that it does work, then it is "up in the air" as
to matters like which heap the object is located in, ... resulting in a high
risk of crashes. multiple heaps may exist behind the scenes, and bad things
may take place if one mixes memory between them.

delete and RTTI are similar, as delete generally needs to be within the same
DLL as the call to 'new', and RTTI generally only works if the place where
it is used is in the same DLL as where the 'new' was done.

the result is that operations like new, delete, dynamic_cast, ... may need
to be wrapped (say, with plain old functions, maybe methods in another
class, ...).


note that most of these problems are Windows specific (and depend some on
ones' choice of compiler, ...), and so, on Linux these operations are a
little safer...


my personal bias though, as noted before, is to simply "drive a hard wedge"
between DLL's and the outside world, as IME this typically both works out
best, and seems to be generally how DLL's were designed to operate. there is
little technical reason it all has to work this way, and in many 3rd party
frameworks, it doesn't work this way, but MS decided to make everything work
this way, and probably they have some good reason for doing so (it seems to
me to mostly revolve around helping to both maintain backwards compatibility
and also to some extent "futureproofing", since stuff starts blowing up in
ones' face mostly when one starts using practices which could risk breaking
compatibility later on, but this is mostly speculation...).

even C# has silly little rules that serve no real purpose apart from to try
to disambiguate things in the case of a possible version mismatch (the usage
patterns of the new/virtual/override keywords, ...). so, in general, this is
something they tend to take seriously, and I suspect with good reason.


or such...
 
J

James Kanze

On 03/09/2010 17:53, Lars Tetzlaff wrote:
In some circumstances (I forget what!) each DLL has its own
heap.

Only if you want it too. If the DLL's all have separate heaps,
and that's not what you wanted, then you've given the wrong
commands to the linker.
If you call new you get memory from the heap for that DLL.
It's then a good idea to call delete from the same dll, and
put it back into the same heap. Or Bad Things Happen.
You'd be better with a Windows-specific newsgroup.

In theory, at least, the same problems can happen under Unix.
(In practice, it won't happen for new, because new will only
call malloc, which is in libc under Unix, and most Unix systems
don't have a libc.a, only a libc.so.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,782
Latest member
ThomasGex

Latest Threads

Top