为何带多余类名限定的C++代码可被GCC正常编译?
测试环境
- 操作系统:CentOS 8
- 编译器版本:GCC 8.5.0 20210514 (Red Hat 8.5.0-4)
观测到的编译现象
C++编码过程中存在如下特殊编译表现:
- 成员函数实现的限定名中多写1层
Person类限定,甚至叠加多层Person限定,代码都可无错误、无警告编译通过 - 如果将限定名错写为
one::one::Person::set_name,GCC会直接抛出编译错误
对编译生成的目标文件person.o执行nm -C命令查看符号表,输出结果如下:
0000000000000000 T one::Person::set_name(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
从符号输出可以判断,编译器会自动“折叠”重复的类作用域,将多层重复的Person类作用域合并为单个类作用域。
复现代码
头文件 person.h
// header file #include <string> namespace one { class Person { public: void set_name(const std::string& name); void set_age(int age); private: std::string name_; int age_; }; }
实现文件 person.cpp
// implementation #include "person.h" // 下方函数定义的限定名中多写了一层Person void one::Person::Person::set_name(const std::string& name) { name_ = name; }
原理说明
这个表现是C++标准规则下的正常行为,核心是注入类名机制:
- 每个类完成定义后,类名会被自动注入到自身的作用域中,成为该作用域下可直接访问的合法名称
- 当写出
one::Person::这层限定后,名称查找逻辑就已经进入了Person类的作用域范围,此时后续写出的Person,会被解析为类自身的注入类名,语义上等价于类本身 - 叠加多层
Person::Person::...的写法,本质上是反复通过注入类名定位到同一个类,最终编译器解析后的语义和单层Person::完全一致,因此可以正常编译,生成符号时也会自动合并为正确的单层类作用域符号 - 错写
one::one::Person::set_name时触发编译错误,是因为one是命名空间,命名空间不存在注入类名的自动等效机制,one命名空间下没有嵌套定义另一个同名的one命名空间,名称查找时找不到对应作用域,就会直接报错。
内容的提问来源于stack exchange,提问作者Xiaoyong Guo
相关产品推荐
相关产品推荐

