C++不同类指针指向异类对象调用成员方法的内存原理
为什么跨类强制转换的指针依然能调用对应类的非虚成员函数
你观察到的运行结果,本质是C++非虚成员函数的调用机制与对象内存布局共同作用的结果,核心逻辑如下:
- 非虚成员函数的指令不会存储在类对象的内存空间中。普通成员函数在编译阶段就会被确定唯一的内存入口地址,编译后本质是一个隐式携带
this指针作为首参数的普通函数。以你代码中的volume方法为例,编译后生成的逻辑等价于:
// 编译器对Cylinder::volume的底层改写 double Cylinder_volume(Cylinder* this) { return 3.14 * this->radius * this->radius * this->height; }
当你写pcyl->volume()时,编译器只需要根据指针的静态类型Cylinder*,直接跳转到编译期就固定的Cylinder_volume入口执行即可,完全不需要去pcyl指向的内存块里查找函数指令,自然不会因为指向的是Triangle对象就找不到volume方法。
- C风格强制类型转换仅修改了编译器对指针指向内存的解析规则,没有改动内存中的实际数据。你定义的
Cylinder和Triangle类内存布局完全一致:对象首地址开始连续排列两个double类型成员变量,每个double占8字节,第一个成员偏移为0,第二个成员偏移为8字节。当Cylinder_volume执行时,会按照Cylinder的内存布局,从传入的this指针(即triangle1的首地址)偏移0位置取第一个double作为radius,偏移8位置取第二个double作为height,刚好读到Triangle对象存储的base和height值,因此能顺利完成计算,不会触发内存访问错误。 - 你预期的程序崩溃、错调Triangle类
area方法的场景,只会在类包含虚函数时出现。虚函数的调用地址存储在对象内存头部的虚表指针指向的虚函数表中,调用时需要运行时从对象内存读取地址跳转,跨类强转后才可能出现非法地址访问、跳转到错误函数的问题。你测试的两个类都没有虚函数,对象内存中不存在虚表相关结构,函数调用地址完全是编译期硬编码的,因此不会出现跳错函数的情况。
该写法属于C++标准明确规定的未定义行为,不同编译器、不同编译优化等级下都可能产生完全不同的运行结果,仅可用于底层机制探究,严禁在生产环境中使用。
附测试涉及的核心代码:
// Cylinder类定义 class Cylinder { public: Cylinder(double r, double h) { radius = r; height = h; } double volume() { return 3.14*radius*radius*height; } private: double radius{1}; double height{1}; }; // Triangle类定义 class Triangle { public: Triangle(double b, double h) { base = b; height = h; } double area() { return 0.5*base*height; } private: double base{1}; double height{1}; }; // 测试main函数 int main() { Cylinder cylinder1(4,5); Triangle triangle1(6,9); cout<<"Volume is " << cylinder1.volume() << endl; cout<<"Area is " << triangle1.area() << endl; Cylinder *pcyl = (Cylinder*)&triangle1; cout << "Address of Triangle" << &triangle1 << endl; cout << "pcyl is pointing to "<< pcyl << endl; cout<<"Cross-call result is " << pcyl->volume() << endl; return 0; }
内容的提问来源于stack exchange,提问作者Swanand
相关产品推荐
相关产品推荐

