命名空间和静态类成员链接
Namespace and static class members linking
我有两个文件:
/**
* class.cpp
*/
#include <stdio.h>
class foo
{
private:
int func();
};
int foo::func(void)
{
printf("[%s:%d]: %sn", __FILE__, __LINE__, __FUNCTION__);
return -1;
}
和
/**
* main.cpp
*/
#include <stdio.h>
namespace foo
{
int func(void);
}
int main(void)
{
int ret = foo::func();
printf("[%s:%d]: ret=%dn", __FILE__, __LINE__, ret);
return 0;
}
编译如下:
g++ -o a.out main.cpp class.cpp
可执行文件有一个输出:
[class.cpp:15]: func
[main.cpp:14]: ret=-1
最后我的问题是:
为什么这个示例代码编译没有任何错误,我们能够调用类foo的private方法?
编译与gcc 4.6.3但不只是。我知道编译器不会区分这两个符号(func function与命名空间foo,私有函数foo与类foo)。nm的输出:
nm class.o
00000000 T _ZN3foo4funcEv
00000017 r _ZZN3foo4funcEvE12__FUNCTION__
U printf
nm main.o
U _ZN3foo4funcEv
00000000 T main
U printf
我想问一下这种行为是否正确?恕我直言,这不是正确的行为,而且根本不安全(破坏封装)。
我想说的是,visual studio 2008的编译器不链接这两个符号。
为什么编译器不报错?
注意"class", "struct"answers"namespace"在编译器看来都定义了一个命名空间。因此编译器相应地装饰符号。如果在同一个文件中定义了类和命名空间,它会报错,但是这里不是这种情况。
为什么链接器没有报错?
您编写代码的方式,使namespace foo
中定义的func()
弱于class foo
中定义的func()
。基本上,namespace foo
中定义的func()
只是一个没有实现的签名。您可以看到,它留给链接器在运行时解析符号,因为实现不在main.cpp
:
nm main.o
U _ZN3foo4funcEv
//Here^^^^
这样,由于命名空间和类名碰巧是相同的(导致foo::func
的符号相同),链接器在链接时解决符号,找到具有相同符号的强定义,并针对它进行链接。
如果你要在namespace foo
中实现func()
:
/**
* main.cpp
*/
#include <stdio.h>
namespace foo
{
int func(void) {
printf("NM_FOO [%s:%d]: %sn", __FILE__, __LINE__, __FUNCTION__);
return -1;
};
}
int main(void)
{
int ret = foo::func();
printf("[%s:%d]: ret=%dn", __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
如果你看主。这次你会看到:
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
两者都定义了同样强的函数符号,导致链接器错误。
请记住,链接器并不知道名称空间和类之间的区别。它解析目标代码中的符号。如果发生强烈的重新定义,它只会抱怨。
因为您已经将foo()
定义为main.cpp中名称空间的成员,所以编译器就是这样处理它的。类/结构/命名空间public/private等之间的区别取决于编译器知道函数的定义——这里你故意欺骗它。
链接器不知道这些区别,它只是解析符号名,在编译器的情况下,函数名的修饰也是一样的。符号名的修饰方式在c++中是未指定的,所以这是完全有效的行为。
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 类和类成员的链接
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- C++ - 使用 std::list,如何打印对象的私有成员的链接列表?
- C++标准是否定义了结构中成员函数的函数内定义是否必须具有静态链接?
- 单独库中的类成员函数定义和链接依赖项
- emplace_back会导致静态 constexpr 成员上出现链接错误
- 类中常量成员函数的 c++ 链接错误
- C :(不重复)积分静态成员初始化(不仅是声明!),导致链接器错误,原因
- 获取 constexpr 全局变量(不是静态成员)的链接器符号
- 使用 <filesystem> C++17 中的成员的链接错误
- gcc 和 clang 中 constexpr 静态成员变量的链接器错误
- (C++)(链接错误)模板成员函数上未解析的外部
- 静态成员函数访问静态私有变量时的链接器错误
- 关于在 ndk r15 中的类中初始化的静态成员的不满意链接错误
- 为什么添加静态数据成员会导致链接器失败
- 类模板的成员函数模板找不到定义,尽管存在显式实例化。不链接
- C++ 使用 .chain().method() 链接成员函数 vers ->chained(0->method()
- 静态成员初始化链接错误
- 链接器为某些上下文中使用的集成静态常量成员提供错误"undefined symbol"