Ответ 1
Почему компилятор не жалуется?
Обратите внимание, что "класс", "struct" и "namespace" все определяют пространство имен в отношении компилятора. Таким образом, компилятор соответствующим образом украшает символы. Он будет жаловаться, если вы определите как класс, так и пространство имен в том же файле, но здесь это не так.
Почему линкер не жалуется?
То, как вы написали код, оставляет func()
, определенный в namespace foo
слабее, чем func()
, определенный в class foo
. В принципе, func()
, определенный в namespace foo
, является просто сигнатурой без реализации. Вы можете видеть, что для компоновщика это разрешено разрешать символ во время выполнения, потому что реализация не находится в main.cpp
:
nm main.o
U _ZN3foo4funcEv
//Here^^^^
Таким образом, поскольку имена пространства имен и классов были одинаковыми (приводя к тем же символам для foo::func
), компоновщик решает символ в момент ссылки, находит сильное определение с тем же символом и ссылки на него.
Если вы должны были реализовать func()
в namespace foo
:
/**
* main.cpp
*/
#include <stdio.h>
namespace foo
{
int func(void) {
printf("NM_FOO [%s:%d]: %s\n", __FILE__, __LINE__, __FUNCTION__);
return -1;
};
}
int main(void)
{
int ret = foo::func();
printf("[%s:%d]: ret=%d\n", __FILE__, __LINE__, ret);
return 0;
}
Вы бы увидели, что компоновщик жалуется:
duplicate symbol foo::func() in:
/var/folders/.../class.o
/var/folders/.../main.o
ld: 1 duplicate symbol for architecture x86_64
Если вы посмотрите на main.o на этот раз, вы увидите:
0000000000000064 T __ZN3foo4funcEv
0000000000000158 S __ZN3foo4funcEv.eh
00000000000000e0 s __ZZN3foo4funcEvE12__FUNCTION__
0000000000000000 T _main
0000000000000128 S _main.eh
U _printf
И class.o:
0000000000000000 T __ZN3foo4funcEv
00000000000000a0 S __ZN3foo4funcEv.eh
0000000000000080 s __ZZN3foo4funcEvE12__FUNCTION__
U _printf
оба из них определяют одинаковый символ функции одинаково сильным, что приводит к ошибке компоновщика.
Помните, что компоновщик не знает о различии между пространством имен и классом. Он разрешает символы, которые находятся в объектном коде. Он будет жаловаться только на сильные переиделения. Одно или несколько более слабых определений с одним сильным определением прекрасно подходят в мире компоновщиков.