GCC环境下C++共享库类继承场景符号可见性问题咨询
问题1解答
案例4没有报未定义引用的核心原因是虚函数调用走间接分发,不需要客户端直接链接析构函数的符号:
- 当析构函数声明为虚函数后,客户端执行
delete s时,不会生成直接调用Foo::~Foo()符号的代码,而是先取s指向的对象头中的虚表指针,从虚表中读取析构函数的地址再调用。 - 你返回的
Foo实例是在共享库内构造的,虚表指针由库代码初始化,指向库内部编译生成的Foo虚表,析构函数的地址已经提前填到虚表对应的位置,整个过程不需要客户端侧对Foo::~Foo()符号做直接引用,自然不会触发未定义引用错误。 - 这种行为不属于未定义行为,完全符合GCC遵循的Itanium C++ ABI规范,只要你的运行环境满足你给出的3个前提条件,运行逻辑是稳定可靠的。
问题2解答
仅导出抽象基类和工厂函数、隐藏所有派生类的做法完全合规,并且是C++共享库开发的最佳实践之一:
- 你导出的抽象基类
Foo已经包含了所有客户端需要的接口声明,客户端所有调用都通过基类的虚函数表做间接分发,不需要知道派生类Bar的存在,更不需要链接Bar相关的任何符号。 - 这种做法刚好符合GCC符号可见性规则的设计初衷:隐藏所有不需要对外暴露的实现细节,既可以减小共享库的体积、加快加载速度,还能大幅提升ABI兼容性——后续你修改
Bar的实现、新增派生类都不需要修改对外的头文件,也不会破坏旧版本客户端的兼容性。
内容的提问来源于stack exchange,提问作者admo
相关产品推荐
相关产品推荐

