I wanted to experiment with external linking and incomplete type declarations and wrote this example:
Source.cpp:
//Source.cpp
class A {
public:
int a=10;
};
A* var1 = new A();
void printA(A* arg)
{
cout << arg->a << endl;
}
Source1.cpp:
//Source1.cpp
class A
{
public:
int b = 20;
int c = 30;
};
A* var2 = new A();
void printB(A* a)
{
std::cout << a->b;
}
main.cpp:
//main.cpp
class A;
extern A* var1;
extern A* var2;
int main()
{
void printA(A*);
void printB(A*);
printA(var1); //Prints 10
printA(var2); //Prints 10
printB(var2); //Prints 10
return 0;
}
After the first call of printA()
"10" is printed just as I expected. But why "10" is also printed after the second call of printA()
and printB()
?
Welcome to the wonderful world of One Definition Rule violations. You have two classes, both defined at file scope, sharing a name.
Since classes have external linkage by default, you have two definitions for the same class, that don't agree with each-other. That makes your program ill-formed, the compiler/linker can complain, or just go ahead and do weird things.
On the flip side, the way to force internal linkage for a class is to declare it in an unnamed namespace:
namespace {
class A {
public:
int a=10;
};
}
Since unnamed namespaces are unique to each translation unit, you will in fact have two separate class definitions. The caveat is that you can't declare extern
variables to them from outside the translation unit anymore.