I can not fully understand the code result when exist override ambigous function.
I have a libray libMy
, which contains two class A
and B
.
The code shows as follows
// A.h
#ifndef included_A_h
#define included_A_h
class A
{
public:
void print();
};
#endif
// A.cpp
#include "A.h"
#include <iostream>
void A::print()
{
std::cout << "A from library" << std::endl;
}
// B.h
#ifndef included_B_h
#define included_B_h
class A;
class B
{
public:
void printA(A &a);
};
#endif
// B.cpp
#include "B.h"
#include "A.h"
void B::printA(A &a)
{
a.print();
}
I have two main function, they can generate two executable file with the library.
It can be found that Main*.cpp looks strange. Why need look like so is explained at the bottom.
// MainUsingCPP.cpp
#include <iostream>
#define included_A_h
class A
{
public:
void print()
{
std::cout << "A from Main" << std::endl;
}
};
#include "B.cpp" // note: using B.cpp here
int main()
{
A obj_a;
B obj_b;
obj_b.printA(obj_a);
return 0;
}
// MainUsingH.cpp
#include <iostream>
#define included_A_h
class A
{
public:
void print()
{
std::cout << "A from Main" << std::endl;
}
};
#include "B.h" // note: using B.h here
int main()
{
A obj_a;
B obj_b;
obj_b.printA(obj_a);
return 0;
}
With follow line, we can compile the library, and generate executable file.
# generate library
g++ -c A.cpp
g++ -c B.cpp
ar -crv libMy.a A.o B.o
# compile case CPP
g++ MainUsingCPP.cpp -L . -lMy -o MainUsingCPP
# compile case H
g++ MainUsingH.cpp -L . -lMy -o MainUsingH
And run the executable file, result shown as follow
./MainUsingH
A from library
./MainUsingCPP
A from Main
My problem is that:
(1)Why the code can compile?
Taken MainUsingCPP.cpp
and library into consideration, the class A is redefined. So we have two A::print()
version. The one from MainUsingCPP.cpp
and another from library. At these stage, the A::print()
is ambigous. Why the code can compile? How the linker distinguish them? How the linker decide which version of function it needs to use?
(2)How to understand the result?
Why the result in two executable file different?
Why the linker choose A::print()
from library in MainUsingH.cpp
and choose A::print()
from Main in MainUsingCPP.cpp
Why Main.cpp looks strange
A
is a class and B
is A
's user. In MainUsingCPP.cpp
, the A
's funtion seems can be redefined. That is, A
is can be mocked for unit test even if A do not have virtual function!
More can see Peter Dotchev's answer in the fake/mock nonvirtual C++ methods
Thanks for your time!
(1)Why the code can compile?
The One Definition Rule says that
Only one definition of any variable, function, class type, enumeration type, ... or template is allowed in any one translation unit
and this is satisfied, because each object file corresponds to a different translation unit.
So much for compilation (of translation units to object files) - now for linking:
One and only one definition of every non-inline function or variable ... is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.
So your program behaviour is undefined, but the compiler is not required to tell you, or even to determine this itself.
(2)How to understand the result?
Stop trying to understand Undefined Behaviour, it's undefined by definition.
If you want to understand what your specific compiler did with your broken code, then get it to expand the two main translation units for you (using -E
for GCC). But, it's really a question about your compiler rather than the language, since the language explicitly didn't define this situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With