I am working on a Visual studio project
header.h
class A
{
virtual int __cdecl funct1() = 0;
};
Project B(which generates a DLL on compilation)
//projectBheader.h
#include<header.h>
#define projectBclass_DLL __declspec( dllexport )
class projectBclass_DLL projectBclass: public A
{
virtual int __cdecl funct1();
}
//projectBheader.cpp
A::int __cdecl projectBclass::funct1()
{
//definition goes here
}
but it is giving error
error C2695: 'projectBclass::funct1': overriding virtual function differs
from 'A::funct1' only by calling convention
Thanks in advance
Short version:
Maybe you have to use public access modifiers.
Long version:
Just a wild guess, but maybe you have got an accessibility problem, not a calling convention problem. I was surprised to see that one can export private class members, but maybe you cannot after all? (please correct me if I am wrong)
According to MSDN, "To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name ..." as you did.
The default scope is private, though.
Related
I discovered this little gotcha with virtual functions and DLLs, and thought I would share what I learned about it.
Let's say that you have two projects, called Alpha and Bravo. Alpha is built as a DLL, to which Bravo references. Now, in Alpha, you have the base class:
Header file: (Alpha.h)
#pragma once
#if defined(EXPORT_ALPHA)
#define ALPHA_API __declspec(dllexport)
#else
#define ALPHA_API __declspec(dllimport)
#endif
class BaseClass
{
public:
ALPHA_API BaseClass();
ALPHA_API virtual ~BaseClass();
virtual void Foo();
};
Cpp file: (Alpha.cpp)
#include "Alpha.h"
#include <cstdio>
BaseClass::BaseClass() {}
BaseClass::~BaseClass() {}
void BaseClass::Foo()
{
printf( "Foo\n" );
}
Then, in Bravo, you have the derived class and main (call it main.cpp):
#include "Alpha.h"
#include <cstdio>
class DerivedClass : public BaseClass
{
public:
DerivedClass() : BaseClass() {}
virtual ~DerivedClass() {}
};
int main()
{
DerivedClass* derived = new DerivedClass();
printf( "Created instance of derived class.\n" );
delete derived;
return 0;
}
Now, Alpha builds successfully, generates its DLL, and goes on its merry way. But then, you go to build Bravo, and you get LNK2001 - unresolved external symbol BaseClass::Foo(), even if you never actually use it.
So, what is happening? Why is it generating a linker error if we never call Foo()?
It is due to how the virtual table is populated by the linker. When you are linking Alpha, it has both the declaration of the virtual function, and since it knows where the assembled code for Foo() is, it just populates the BaseClass's virtual table with the address of the assembled code. But, since Foo() is not exported, it doesn't add an entry for the function to the corresponding lib. So, for instance, if a DLL and static lib were compiled with comments, they might look something like this:
Alpha.dll:
# this is BaseClass's virtual table, located at some random address only known internally
0x00002000 # Function address of ~BaseClass()
0x00004000 # Function address of Foo()
# This is the machine code for Foo(), located at address 0x00004000
mov eax, [ebx]
add eax, ecx
...
Alpha.lib:
# Exports:
BaseClass()#BaseClass : 0x00001000 # Address in the DLL of the constructor
~BaseClass()#BaseClass : 0x00002000 # Address in the DLL of the destructor
When it goes to link Bravo, it knows that it needs to add an entry for Foo() to DerivedClass's virtual table. (It knows because the compiler told it when it read the included headers.) So, first, the linker looks for a compiled function called Foo()#DerivedClass. There isn't one, so then it looks for a compiled function called Foo()#BaseClass. However, the static lib does not have an entry for Foo()#BaseClass, because Alpha did not export it. Thus, the linker doesn't find any entries for Foo()#BaseClass, and therefore cannot populate DerivedClass's virtual table with a function address for Foo().
This means that you will get the linker error in the downstream project. It also means that if DerivedClass provides an implementation for Foo(), this linker error will not occur unless that implementation attempts to call the base class's implementation. However, the right way to fix this is to make sure you export all virtual functions in a class that might have derived classes in downstream projects (either that, or export the class itself).
I'm getting a linker warning caused by virtual destructors. My environment is the KEIL compiler v6.5 (clang).
Warning: L6439W: Multiply defined Global Symbol __clang_call_terminate defined in invalid_group(new.cpp.o) rejected in favor of Symbol defined in .text.__clang_call_terminate(cxa_handlers.cpp.o).
I get this warning as soon as I add the virtual destructor to an interface. For example:
class IInterface {
virtual ~IInterface(){}
virtual void doSomething() const = 0;
}
As soon as I implement one single derived class of this interface I get the above mentioned warning. As soon as I remove the virtual destructor, the warning vanishes.
I tried really many things to find out what's the reason, but didn't succeed...
Does someone know how to fix this warning?
Thank you!
Edit: A complete example throwing this warning:
class IInterface {
public:
virtual ~IInterface();
virtual void doSomething() = 0;
};
IInterface::~IInterface() {
}
class SomeClass : public IInterface {
public:
virtual void doSomething();
};
void SomeClass::doSomething() {
}
int main() {
}
I asked support of ARM and got the information that this warning is spurious. So it seems to be an issue of the current ARM clang compiler toolchain implementation.
Nevertheless thank you all for your responses on this topic.
If you define your function in header you will emit the function each time you include it in a file. To remove this warming you need to define your method outside the declaration
// IInterface.hpp
class IInterface {
public:
virtual ~IInterface();
}
// IInterface.cpp
IInterface::~IInterface() {}
As mentioned, this was a linker bug which has been fixed in ARM Compiler v6.11 (10/25/2018).
Release notes:
[SDCOMP-30157] In certain circumstances, after discarding a section from a COMDAT ELF section group, the linker could incorrectly report Warning: L6439W: Multiply defined Global Symbol defined in invalid_group() rejected in favour of Symbol defined in (). This has been fixed.
recently we encountered in our legacy code that is currently ported from VS2010 to VS2015 an interesting effect. Unfortunately I couldn't create a small example that shows this effect, but I'll try to describe it as accurately as I can.
We have 2 dlls (I'll call them dll A and dll B). The project for dll A defines the interface IFoo & a derived interface IFxFoo
class __declspec(novtable) IFoo {
public:
virtual int GetType() = 0;
virtual ~IFoo() {}
};
class __declspec(novtable) IFxFoo : public IFoo {
public:
virtual int GetSlot() = 0;
};
in dll B, both interfaces are used.
class CBImpl : public IFxFoo {
public:
...
void processFoo(IFoo* f) {
...
if (f->GetType() == IFXFOO) {
IFxFoo* fx = static_cast<IFxFoo>(f); //downcast
fill(fx);
}
}
void fill(IFxFoo* fx) {
m_slot = fx->GetSlot();
}
private:
int m_slot;
};
processFoo() will be called with different implementations of IFoo. Some from dll A and some from dll B.
What now happened was the following:
- if we turned on whole program optimization when compiling dll B, the call to the virtual function GetSlot() in function fill() got de-virtualized by Visual C++. This caused our program to crash.
we can fix this behavior if we either
turn of whole program optimization
turn of optimization for fill
or mark our interfaces with __declspec(dllimport) / __declspec(dllexport)
The questions that I have now are:
is our assumption correct that the de-virtualization happened because the optimizer saw only one implementation of IFxFoo in dll B and assumed that this is the only one because IFxFoo was not marked to be from a different dll?
what's the best way to create "interfaces" in header files? We used to do them like above but this seems to lead to some problems.
do other compiler (gcc / clang) exhibit similar behavior?
Thank you for your help
Tobias
Using LTO results in the compiler making drastic adjustments to any functions for which is it able to see the complete callgraph.
What you are seeing is expected and using __declspec(dllexport) or extern on the functions that need to be utilised from a separate module or explicitly declaring them as part of a DLL .def file is the expected way to resolve the problem as the compiler will no longer consider the functions to be internal-only.
Prior to refactoring my previous question, which I believe was a little bit off...
The title pretty much asks my question.
How can I keep a class definition on it's own without giving it methods & producing the error below?
The reason for this is because I want to create an object in a separate DLL (which contains the methods), but only return a reference pointer to my main program.
This is explicit exporting by the way.
Error 1 error LNK2001: unresolved external symbol "public: int
__thiscall ObjTest::getValue(void)" (?getValue#ObjTest##QAEHXZ)
class ObjTest
{
private:
int x;
public:
int getValue();
};
Since you need to load the .dll with LoadLibrary(), you can expose a pure virtual class, and have the .dll return a sub class of it:
You separate them in two files:
File ObjTest.h:
class ObjTest
{
public:
virtual int getValue() = 0;
};
ObjTest *CreateObjTest();
File ObjTest.cpp:
#include "ObjTest.h"
class ObjTestImpl : public ObjTest
{
int x;
public:
virtual int getValue();
};
int ObjTestImpl::getValue()
{
return x;
}
ObjTest *CreateObjTest()
{
return new ObjTestImpl();
}
You compile ObjTest.cpp and create a .dll out of it. Your main executable program will need to LoadLibrary() your .dll, use GetProcAddress() to extract the CreateObjTest as a function pointer and call it to return a new ObjTest .
(You might have to create a DeleteObjTest() function too - if your main executable and .dll end up with a different CRT, they'll have different heaps, so you need to call into the .dll instead of just doing delete myObj.)
The other approach is to wrap everying in a C API, and just pass opaque handles to C functions across the .dll instead of dealing with C++ objects.
You are confusing definition and implementation. You have the method defined but not implemented. Hence, the compiler compiles the code without error, as the method is defined, the linker creates an error as there is no implementation for the method (undefined symbol).
The DevStudio compiler does let you import classes from DLLs into an application:-
class __declspec (dllimport) ClassName
{
// members, etc
}
and in the DLL source, change the 'dllimport' to 'dllexport'.
See this MSDN article for more information.
If you want to hide the data members and the private methods then you'd need to look into the pimpl idiom.
I am creating a new abstract class in C++/CLI and have run into a strange error. There are many questions similar to this one but none of the answers could help me.
In this new class, I get the following error:
error LNK2020: unresolved token (06000002) Foo::execute
This is the h-file:
#pragma once
using namespace System::IO::Ports;
using namespace System;
public ref class Foo
{
protected:
SerialPort^ port;
public:
Foo(SerialPort^ sp);
virtual array<Byte>^ execute();
};
This is the cpp-file:
#include "StdAfx.h"
#include "Foo.h"
Foo::Foo(SerialPort^ sp)
{
this->port = sp;
}
Note that when I comment out the virtual array<Byte>^ execute(); line, everything compiles perfectly. Also, when I remove the virtual modifier and add an implementation of execute() in the cpp-file, it works as well.
You already gave the answer yourself:
Also, when I remove the virtual modifier and add an implementation of execute() in the cpp-file, it works as well.
You declared the method execute in the header, but it's implementation is missing. That's exactly what the linker error is telling you.
In this case the declaration as virtual does not matter.
If you want to create an abstract class, you can find further details in numerous articles online (e.g. Wikibooks: Abstract Classes)
You have to either implement the method or remove the declaration from the header. (virtual keyword doesn't matter in this case)
Please, ask a question, if you have any.