none
function at class member in dll can not be called

    Question

  • Hi,  I write a simple DLL with a class(CExportClassDll), and the class has a member(CTest m_test), CTest only has a function(fun). and the calling code CExportClassDll a; a.m_test.fun();

    the error message when compiling is : error LNK2019: unresolved external symbol "public: void __thiscall CTest::fun(void)" 

    the source code are:

    ExportClassDll.h

    // The following ifdef block is the standard way of creating macros which make exporting 
    // from a DLL simpler. All files within this DLL are compiled with the EXPORTCLASSDLL_EXPORTS
    // symbol defined on the command line. This symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see 
    // EXPORTCLASSDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef EXPORTCLASSDLL_EXPORTS
    #define EXPORTCLASSDLL_API __declspec(dllexport)
    #else
    #define EXPORTCLASSDLL_API __declspec(dllimport)
    #endif
    
    
    class CTest
    {
    public:
    	void fun();
    };
    
    
    // This class is exported from the ExportClassDll.dll
    class EXPORTCLASSDLL_API CExportClassDll
    {
    public:
    	CExportClassDll(void);
    	// TODO: add your methods here.
    
    public:
    	CTest m_test;	
    };
    

    ExportClassDll.cpp

    // ExportClassDll.cpp : Defines the exported functions for the DLL application.
    //
    
    #include "stdafx.h"
    #include "ExportClassDll.h"
    
    
    
    void CTest::fun()
    {
    }
    
    
    // This is the constructor of a class that has been exported.
    // see ExportClassDll.h for the class definition
    CExportClassDll::CExportClassDll()
    {
    	return;
    }
    

    the _tmain code

    // ExportClass.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "../ExportClassDll/ExportClassDll.h"
    
    #pragma	comment(lib, "../Debug/ExportClassDll.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	CExportClassDll a;
    	a.m_test.fun();
    	
    	return 0;
    }
    

    it's np if I update CTest::fun() into ExportClassDll.h file like

    class CTest
    {
    public:
    	void fun()
    	{
    		;
    	}
    };

    it's np if I export CTest like

    class EXPORTCLASSDLL_API CTest
    {
    public:
    	void fun();
    };
    

    it's np if I update "CTest m_test;" to "CTest * m_pTest;" and update "void fun();" to "virtual void fun();"

    and update _tmain code as a.m_pTest->fun();

    class CTest
    {
    public:
    	//void fun();
    	virtual void fun();
    };
    
    
    // This class is exported from the ExportClassDll.dll
    class EXPORTCLASSDLL_API CExportClassDll
    {
    public:
    	CExportClassDll(void);
    	// TODO: add your methods here.
    
    public:
    //	CTest m_test;
    	CTest * m_pTest;
    };
    

    who knows why? thanks advance

    Tuesday, September 24, 2013 1:23 AM

Answers

  • But we have to update all CTest function as virtual, it's not a good class design.

    More generally, it is not a good design to export a C++ class across a DLL boundary at all. This binds you to the specific version of the compiler, for both the DLL and the client code. In other words, you have to compile both the DLL and the client code with exactly the same compiler and exactly the same compiler switches. Experienced C++ programmers know this, and design a DLL with a C-style interface only, using POD data types as parameters. Another alternative is a COM DLL which lets client code of any language type to call the DLL (assuming that language is COM-aware).

    • Marked as answer by Jacky Zhou Friday, October 04, 2013 1:56 PM
    Wednesday, September 25, 2013 7:36 PM
  • you will never put implementation in ITest, put all your implementation code in CTest and override all those functions which you want to expose it to the outer world.

    ITest is an interface to your CTest, the client app will never know the inner workings of CTest,  so that you can change the inner workings of the CTest at your will, without worrying about breaking the client

    Sunday, September 29, 2013 3:02 PM

All replies

  • Not surprisingly, not only does your CExportClassDll need to be exported, but the internal class CTest also needs to be exported since the CTest::fun() function in defined in the DLL.

    Also not suprisingly, if you define (not just declare) the void fun() member function in the header file, then your client code does not need it exported. It is already known in the header itself.

    Tuesday, September 24, 2013 2:30 AM
  • Not surprisingly, not only does your CExportClassDll need to be exported, but the internal class CTest also needs to be exported since the CTest::fun() function in defined in the DLL.

    Also not suprisingly, if you define (not just declare) the void fun() member function in the header file, then your client code does not need it exported. It is already known in the header itself.

    and more as I described at last:

    it's np if I update "CTest m_test;" to "CTest * m_pTest;" and update "void fun();" to "virtual void fun();"

    why is it virtual function?

    basically, we do not want end user knows CTest implementation, and we want end user use it by "CTest * m_pTest;", obviously, "CTest m_test;" does not work. And we do not want export CTest for some reason.

    But we have to update all CTest function as virtual, it's not a good class design.

    Wednesday, September 25, 2013 1:51 PM
  • another method to solve your issue

    #ifdef EXPORTDLL_EXPORTS
    #define EXPORTDLL_API __declspec(dllexport)
    #else
    #define EXPORTDLL_API __declspec(dllimport)
    #endif
    
    //In the .h File
    ITest.h
    
    extern "C" EXPORTDLL_API ITest* CreateTestInstance();
    	
    
    class ITest
    {
    public:
    	virtual void Fun1();
    	virtual void Fun2();
    	virtual void Fun3();
    };
    
    class CTest:public ITest
    {
    public:
    	void Fun1()
    	{
    		//develop functionality of Fun1 here
    	}
    
    	void Fun2()
    	{
    		//develop functionality of Fun1 here
    	}
    
    	void Fun3()
    	{
    		//develop functionality of Fun1 here
    	}
    };
    
         ITest* CreateTestInstance()
    	{
    		ITest *ptr = new CTest();
    		if(ptr)
    			return ptr;
    	}
    
    
    //Client side
    #include"Itest.h"
    
    void main()
    {
    	//Client need not know about CTest implementation, you are only distrubuting 
    	//Interface, moreover you can change the CTest implemetion at your will and 
    	//Distrubute any updates, without worying about Client App recompilation
    	//thus avoiding Dll hell.
    	ITest *ptr= CreateTestInstance();
    	ptr->Fun1();
    }
    
    

    Wednesday, September 25, 2013 4:36 PM
  • But we have to update all CTest function as virtual, it's not a good class design.

    More generally, it is not a good design to export a C++ class across a DLL boundary at all. This binds you to the specific version of the compiler, for both the DLL and the client code. In other words, you have to compile both the DLL and the client code with exactly the same compiler and exactly the same compiler switches. Experienced C++ programmers know this, and design a DLL with a C-style interface only, using POD data types as parameters. Another alternative is a COM DLL which lets client code of any language type to call the DLL (assuming that language is COM-aware).

    • Marked as answer by Jacky Zhou Friday, October 04, 2013 1:56 PM
    Wednesday, September 25, 2013 7:36 PM
  • another method to solve your issue

    #ifdef EXPORTDLL_EXPORTS
    #define EXPORTDLL_API __declspec(dllexport)
    #else
    #define EXPORTDLL_API __declspec(dllimport)
    #endif
    
    //In the .h File
    ITest.h
    
    extern "C" EXPORTDLL_API ITest* CreateTestInstance();
    	
    
    class ITest
    {
    public:
    	virtual void Fun1();
    	virtual void Fun2();
    	virtual void Fun3();
    };
    
    class CTest:public ITest
    {
    public:
    	void Fun1()
    	{
    		//develop functionality of Fun1 here
    	}
    
    	void Fun2()
    	{
    		//develop functionality of Fun1 here
    	}
    
    	void Fun3()
    	{
    		//develop functionality of Fun1 here
    	}
    };
    
         ITest* CreateTestInstance()
    	{
    		ITest *ptr = new CTest();
    		if(ptr)
    			return ptr;
    	}
    
    
    //Client side
    #include"Itest.h"
    
    void main()
    {
    	//Client need not know about CTest implementation, you are only distrubuting 
    	//Interface, moreover you can change the CTest implemetion at your will and 
    	//Distrubute any updates, without worying about Client App recompilation
    	//thus avoiding Dll hell.
    	ITest *ptr= CreateTestInstance();
    	ptr->Fun1();
    }
    

    It has the same problem I think

    If ITest has some functions which are not virtual, then the client app can not use those functions

    Sunday, September 29, 2013 2:44 PM
  • you will never put implementation in ITest, put all your implementation code in CTest and override all those functions which you want to expose it to the outer world.

    ITest is an interface to your CTest, the client app will never know the inner workings of CTest,  so that you can change the inner workings of the CTest at your will, without worrying about breaking the client

    Sunday, September 29, 2013 3:02 PM
  • you will never put implementation in ITest, put all your implementation code in CTest and override all those functions which you want to expose it to the outer world.

    ITest is an interface to your CTest, the client app will never know the inner workings of CTest,  so that you can change the inner workings of the CTest at your will, without worrying about breaking the client

    in fact, I wrote the class named ITest, as an interface already, and the interface is not an abstract virtual class, it includes some un-virtual functions, those un-virtual functions are implemented in ITest.cpp, client will not see the implementation. And I happened to the problem that client can not use those un-virtual functions.  
    Friday, October 04, 2013 1:56 PM
  • in fact, I wrote the class named ITest, as an interface already, and the interface is not an abstract virtual class, it includes some un-virtual functions, those un-virtual functions are implemented in ITest.cpp, client will not see the implementation. And I happened to the problem that client can not use those un-virtual functions.  

    An interface should contain only pure virtual functions. If a client needs to use a function, make it pure virtual in the interface and implement it in the derived class.

    David Wilkinson | Visual C++ MVP

    Friday, October 04, 2013 2:11 PM
  • Hi

    I just learnt MFS DLL. I have written a simple testing program which indicats that function members of the interface class (i.e. CTest, ITest) do not have to be (pure) virtual functions. If this is the case, how is it a bad design not to have (pure) virtual member functions.

    Thanks

    Chong 


    • Edited by chong kyong kim Saturday, October 05, 2013 4:01 AM modification
    Saturday, October 05, 2013 3:02 AM
  • I just learnt MFS DLL. I have written a simple testing program which indicats that function members of the interface class (i.e. CTest, ITest) do not have to be (pure) virtual functions. If this is the case, how is it a bad design not to have (pure) virtual member functions.

    Yes, you can export non-virtual functions, but that is not an interface. The purpose of using ITest and CTest is to separate the interface form the implementation.

    The big advantage of a pure interface in this context is that the virtual function table is implemented the same way by all compiler versions (and most compilers). This allows binary compatibility, and is the key idea behind COM.


    David Wilkinson | Visual C++ MVP

    Saturday, October 05, 2013 10:39 AM
  • another method to solve your issue

    Yes, this is a good pattern (a simplified version of COM). Note however that only the ITest definition and CreateTestInstance() declaration should be in ITest.h. The other code should be in a separate file (or files) used only in the DLL.

    You also need a mechanism for deleting the instance in the DLL, or you will leak memory. This may be done either by adding a new Delete() method to the ITest interface, or by exporting another function, say DeleteTestInstance(ITest*).

    You header file also lacks include guards.


    David Wilkinson | Visual C++ MVP

    Saturday, October 05, 2013 10:50 AM
  • in fact, I wrote the class named ITest, as an interface already, and the interface is not an abstract virtual class, it includes some un-virtual functions, those un-virtual functions are implemented in ITest.cpp, client will not see the implementation. And I happened to the problem that client can not use those un-virtual functions.  


    An interface should contain only pure virtual functions. If a client needs to use a function, make it pure virtual in the interface and implement it in the derived class.

    David Wilkinson | Visual C++ MVP

    I found sometimes some functions are not pure virtual for interface, eg, initialize member variables function, all the derived classes need not implement it again 
    Monday, October 07, 2013 12:44 AM
  • I found sometimes some functions are not pure virtual for interface, eg, initialize member variables function, all the derived classes need not implement it again 

    An interface does not have data members.

    David Wilkinson | Visual C++ MVP

    Monday, October 07, 2013 1:15 AM
  • I found sometimes some functions are not pure virtual for interface, eg, initialize member variables function, all the derived classes need not implement it again 

    An interface does not have data members.

    David Wilkinson | Visual C++ MVP

    That means I should not call them interface, so what should I call?

    It has some virtual functions, and implemented by deffirent derived classes.

    btw, if it has one un-virtual function named fun(), it looks like:

    fun()
    {
        fun1();
        fun2();
    }

    fun1 and fun2 are virtual functions,  so what now?

    Monday, October 07, 2013 6:00 AM
  • That means I should not call them interface, so what should I call?

    It has some virtual functions, and implemented by deffirent derived classes.

    btw, if it has one un-virtual function named fun(), it looks like:

    fun()
    {
        fun1();
        fun2();
    }

    fun1 and fun2 are virtual functions,  so what now?

    As you say it is just words. Maybe you would prefer to call a class with only pure virtual functions a pure interface, and use interface for a more general concept.

    Your example looks like an implementation detail to me. fun1() and fun2() may be virtual in derived classes, but need not appear in the interface.

    As I said before, the particular advantage of a pure interface in the context of a DLL is that it is compiler independent.


    David Wilkinson | Visual C++ MVP

    Monday, October 07, 2013 9:33 AM