添加-fvisibility=hidden后,普通成员函数编译失败虚函数正常?
当编译动态库librectangle.so时使用-fvisibility=hidden全局隐藏所有符号,仅将get_rectangle()函数通过__attribute__((visibility("default")))导出,编写main.cpp链接该动态库时,调用普通成员函数会出现链接错误,但将成员函数改为虚函数后可正常编译运行,原因如下:
1. 普通成员函数链接失败的核心原因
普通成员函数采用静态绑定机制:
- 编译
main.cpp时,编译器会直接生成对Rectangle::set_values(int, int)和Rectangle::area()的符号引用——因为代码中是通过对象指针直接调用成员函数,编译器在编译期就确定了要调用的函数符号。 - 由于
-fvisibility=hidden的全局设置,未显式标记为visibility("default")的普通成员函数符号会被默认隐藏,动态库librectangle.so中不会导出这些符号。 - 链接阶段,链接器在动态库中找不到对应的导出符号,因此抛出
undefined reference错误。 - 用
nm -C librectangle.so查看符号时,普通成员函数的符号类型为t(本地符号,仅在库内部可见),而非导出的T类型。
普通成员函数版本代码示例
rectangle.h
#pragma once #include <memory> class Rectangle { int width, height; public: void set_values (int,int); int area(); }; std::shared_ptr<Rectangle> __attribute__((visibility("default"))) get_rectangle();
rectangle.cpp
#include "rectangle.h" int Rectangle::area() {return width*height;} void Rectangle::set_values (int x, int y) { width = x; height = y; } std::shared_ptr<Rectangle> __attribute__((visibility("default"))) get_rectangle() { return std::make_shared<Rectangle>(); }
main.cpp
#include "../rectangle/rectangle.h" int main() { auto rectangle = get_rectangle(); rectangle->set_values(2, 3); rectangle->area(); return 0; }
链接错误信息
undefined reference to `Rectangle::set_values(int, int)' undefined reference to `Rectangle::area()'
2. 虚函数能正常工作的核心原因
虚函数采用动态绑定机制:
- 当类包含虚函数时,编译器会为该类生成虚表(vtable),每个类实例会携带一个指向虚表的指针。调用虚函数时,程序会通过对象的虚表指针找到虚表,再从虚表中获取函数地址进行调用,这个过程是在运行时完成的。
- 由于
get_rectangle()是导出的函数,且在动态库内部创建了Rectangle的实例,虚表的符号会被隐式包含在导出的依赖中(虚表与实例绑定,实例通过导出函数返回,因此虚表会被标记为可被外部访问)。 - 编译
main.cpp时,编译器不会直接生成对Rectangle::set_values或Rectangle::area()的符号引用,而是生成通过虚表间接调用的代码,因此链接阶段不需要依赖这些成员函数的导出符号,自然不会出现链接错误。 - 用
nm -C librectangle.so查看符号时,会看到vtable for Rectangle是导出的T类型符号,而虚函数的实现符号虽为本地t类型,但不影响外部调用。
虚函数版本代码示例(修改后的rectangle.h)
#pragma once #include <memory> class Rectangle { int width, height; public: virtual void set_values (int,int); virtual int area(); }; std::shared_ptr<Rectangle> __attribute__((visibility("default"))) get_rectangle();
内容的提问来源于stack exchange,提问作者quanquanquan97
相关产品推荐
相关产品推荐

