1

f1.cpp file contains the code for two simple classes. Class A has the function print() defined inside, class B has the function defined outside.

class A{
public:
    void print(){}
};

class B{
public:
    void print();
};

void B::print(){
}

f1.cpp will generate f1.lib.

f2.cpp contains the header for the two classes and the main() function (and it will link with f1.lib to create f2.exe):

class A{
public:
    void print();
};

class B{
public:
    void print();
};

int main(){
    A a;
    a.print();

    B b;
    b.print();
}

When I compile (in Visual Studio 2019), I get a linking error only for class A:

error LNK2001: unresolved external symbol "public: void __thiscall A::print(void)" (?print@A@@QAEXXZ)
fatal error LNK1120: 1 unresolved externals

It seems that the A::print function is not present as a symbol in the lib.

Initially I thought that is because an internal function definition becomes "inline" by default. But I've tried adding the __declspec(noinline) attribute in front of it and it is still not working.

Do you know why the symbol is not present?

0

2 Answers 2

3

f2.cpp is re-declaring A and B, why?

The B declarations in both files match, which is OK, and the linker will match them up to the external B::print() definition in f1.cpp.

But the A declarations in both files do not match, which is not OK, and is undefined behavior. The A in f1.cpp has its own distinct inline definition for print(), but the A in f2.cpp has a non-inline declaration for print() and there is no matching external definition for the linker to find, hence the error.

f2.cpp should not be re-declaring A or B at all. Use header files instead, eg:

// f1.h

#ifndef F1_H
#define F1_H

class A{
public:
    void print() { ... }
    // or: void print();
};

#endif
// f1.cpp (only if A::print() is not inline)

#include "f1.h"

void A::print() {
    ...
}
// f2.h

#ifndef F2_H
#define F2_H

class B{
public:
    void print();
};

#endif
//f2.cpp

#include "f1.h"
#include "f2.h"

void B::print() {
    ...
}

int main() {
    A a;
    a.print();

    B b;
    b.print();
}

Alternatively:

// f1.h

#ifndef F1_H
#define F1_H

class A{
public:
    void print() { ... }
    // or: void print();
};

class B{
public:
    void print();
};

#endif
//f2.cpp

#include "f1.h"

// uncomment if A::print() is not inline...
/*
void A::print() {
    ...
}
*/

void B::print() {
    ...
}

int main() {
    A a;
    a.print();

    B b;
    b.print();
}
Sign up to request clarification or add additional context in comments.

4 Comments

That's right. How does the complier find the definition of methods in headers if you re-declare classes that shadows declaration in headers
@AyratArifullin the compiler doesn't find the definitions. The linker does.
the same comment as for the answer above: what I don't understand is why the two declarations don't match. I thought that defining a function inside a class or outside of the class is just a choise, and it has nothing to do with how it will compile (if we exclude the "inline" part - and I've tried to force the exclusion with the "__declspec(noinline) attribute".
@CatalinPanait think of what happens if a class with inline method definitions gets declared in 2 separate translation units. Two separate implementations, unless the linker optimizes them together. So it makes sense that an inline definition is treated differently than an external definition at the linker stage (the compiler stage doesn't know any better).
1

Do you know why the symbol is not present?

You have 2 different declarations of class A, which leads to Undefined Behaviour. Those declarations must match. You can make it work by fixing second declaration, but an easier and common way is to put that declaration into a header file and #include it in both .cpp files (or more if they use classes declared).

2 Comments

what I don't understand is why the two declarations don't match. I thought that defining a function inside a class or outside of the class is just a choise, and it has nothing to do with how it will compile (if we exclude the "inline" part - and I've tried to force the exclusion with the "__declspec(noinline) attribute".
@CatalinPanait "what I don't understand is why the two declarations don't match." because they are different, but they must be the same. To put a method inside c lass declaration or not is a choice but you cannot make that choice multiple times for the same class, class definition must be the same for all compilation units aka cpp files, that wht language says.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.