Reputation: 93
Following problem popped up using VS2015: i wanted to make abstract base class, inherit another abstract class in own header, when the abstract inheritance is contained in own header the import/export macro seems to be interpreted wrong so the default constructor for the inheritance is not generated, i dont see it in .lib, additionally when using in an exe project link error occur.
maybe i just have some problem of understanding... but for me it seems to be the definition of the api is correct in "TestDll.h" and wrong in "Inherited.h"
steps to reproduce: i made a project "TestDll" containg following headers including a define INHERITED_IN_SAME_HEADER to switch between inhertiance declaration in same or own header.
header "testdll_api.h":
#pragma once
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
header "TestDll.h":
// include export/import macros
#include "testdll_api.h"
// define INHERITED_IN_SAME_HEADER to 1 to enable Inherited declaration in same header
// define INHERITED_IN_SAME_HEADER to 0 to enable Inherited declaration in own header Inherited.h
#define INHERITED_IN_SAME_HEADER 0
// abstract class containing default constructor and destructor
class TESTDLL_API CTestDll
{
public:
virtual void purevirt() = 0;
protected:
CTestDll()
{}
virtual ~CTestDll()
{}
};
// Inherited class in same header like CTestDll
// works
#if INHERITED_IN_SAME_HEADER
// another abstract class extending
class TESTDLL_API Inherited : public CTestDll
{
public:
virtual void purevirtInherited() = 0;
};
#endif
header "Inherited.h":
#pragma once
#include "TestDll.h"
// strange here when following declaration is used intellisense (and potentially compiler)
// see/uses TESTDLL_API as dllimport instead of dllexport ALTHOUGH WE ARE IN SAME PROJECT?!?!?
// note api definition is fetched indirectly from TestDLL.h which includes itself testdll_api.h
#if !INHERITED_IN_SAME_HEADER
class TESTDLL_API Inherited : public CTestDll
{
public:
virtual void purevirtInherited() = 0;
};
#endif
in same solution i added console application "TestConsoleApplication", referencing "TestDll" project, with just following source:
#include "stdafx.h"
#include "..\TestDll\Inherited.h"
class MyInheritedImpl : public Inherited
{
public:
void purevirt()
{}
void purevirtInherited()
{}
};
int main()
{
MyInheritedImpl mimpl;
return 0;
}
so when i define INHERITED_IN_SAME_HEADER to 1 i will get correct linking of console application, when defining INHERITED_IN_SAME_HEADER to 0 i get following errors:
1>------ Build started: Project: TestDll, Configuration: Debug Win32 ------
1> TestDll.cpp
1> TestDll.vcxproj -> c:\users\chris\documents\visual studio 2015\Projects\TestDll\Debug\TestDll.dll
2>------ Build started: Project: TestConsoleApplication, Configuration: Debug Win32 ------
2> TestConsoleApplication.cpp
2>TestConsoleApplication.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall Inherited::Inherited(void)" (__imp_??0Inherited@@QAE@XZ) referenced in function "public: __thiscall MyInheritedImpl::MyInheritedImpl(void)" (??0MyInheritedImpl@@QAE@XZ)
2>TestConsoleApplication.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall Inherited::~Inherited(void)" (__imp_??1Inherited@@UAE@XZ) referenced in function "public: virtual __thiscall MyInheritedImpl::~MyInheritedImpl(void)" (??1MyInheritedImpl@@UAE@XZ)
2>c:\users\chris\documents\visual studio 2015\Projects\TestDll\Debug\TestConsoleApplication.exe : fatal error LNK1120: 2 unresolved externals
========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Upvotes: 1
Views: 2722
Reputation: 93
For Info: Hans has answered absolutly perfect, i now include headers at least once in the dll project, so the compiler can see my declaration and generate necessary exported constructor/destructor.
it would be nice to be warned (i think only possible via IDE, intellisense) about such problem with something like "class Inherit gets nothing exported" i will suggest this at ms.
Upvotes: 0
Reputation: 941218
This does not have anything to do with VS2015, it is just a simple mistake. The problem is that your DLL project does not #include inherited.h, it only includes TestDll.h. So your DLL cannot possibly export the Inherited
class constructor and destructor, the compiler never saw their declaration.
But when you #include inherited.h in your test app, you claim that the class is imported from the DLL. That's a lie, the DLL does not export it, the linker slaps you about the discrepancy since it cannot find the constructor and destructor you promised would be available.
You'll have to make up your mind about where this class needs to live. If you want it in the DLL then one of the DLL source files must #include inherited.h so the compiler sees __declspec(dllexport) and thus knows it needs to auto-generate the constructor and destructor and export them. If you want the client app to have the definition then you must delete TESTDLL_API from the class declaration. Hard to imagine the latter is the intention, and it would be a breaking change from the way it was done before, it is however not wrong.
Upvotes: 2