C++中通过接口调用接口程序崩溃原因咨询
问题分析:基类指针访问派生类成员导致崩溃的原因
你想要实现“通过接口访问接口”的无类型感知程序,但代码运行崩溃,核心问题出在基类和派生类的同名成员变量隐藏上,下面详细解释两种崩溃写法的原因:
测试代码
#include <iostream> #include <string> using namespace std; class ToyInteractor { public: ToyInteractor() {}; virtual void interFunc() = 0; }; class HorseInteractor : public ToyInteractor { public: HorseInteractor() {}; ~HorseInteractor() {}; void interFunc() override { cout << "We made it inside HorseInteractor!" << endl; }; }; class BirdInteractor : public ToyInteractor { public: BirdInteractor() {}; ~BirdInteractor() {}; void interFunc() override { cout << "We made it inside BirdInteractor!" << endl; }; }; class Toy { public: Toy() {}; ToyInteractor *toyInteractor; virtual void func() = 0; }; class Horse : public Toy { public: Horse() {}; ~Horse() {}; ToyInteractor *toyInteractor = new HorseInteractor(); void func() override { cout << "We made it inside Horse!" << endl; }; }; class Bird : public Toy { public: Bird() {}; ~Bird() {}; ToyInteractor *toyInteractor = new BirdInteractor(); void func() override { cout << "We made it inside Bird!" << endl; }; }; int main() { Horse *horse = new Horse(); Bird *bird = new Bird(); // Works as expected horse->func(); bird->func(); cout << endl; // Also works of course horse->toyInteractor->interFunc(); bird->toyInteractor->interFunc(); cout << endl; // Now suppose we do not know the exact type, but we know it surely has a toy-specific toyInteractor: Toy *someToy = horse; // Works fine: someToy->func(); // 1. idea: Crashes: // someToy->toyInteractor->interFunc(); // 2. idea: Also crashes: // ((HorseInteractor*)(someToy->toyInteractor))->interFunc(); return 0; }
崩溃原因详解
1. someToy->toyInteractor->interFunc(); 崩溃原因
你在基类Toy中声明了ToyInteractor *toyInteractor;,但派生类Horse和Bird里又重新定义了同名的toyInteractor变量——这属于成员隐藏,基类和派生类的toyInteractor是完全独立的两个变量:
- 当用
Horse* horse访问时,操作的是Horse类自己定义的、已经初始化的toyInteractor; - 但当转换为
Toy* someToy后,someToy->toyInteractor访问的是基类Toy中那个未初始化的野指针(基类构造函数没有给它赋值,内存地址随机)。
调用interFunc()时,通过野指针访问非法内存,直接触发崩溃。
2. ((HorseInteractor*)(someToy->toyInteractor))->interFunc(); 崩溃原因
这种写法只是给野指针做了强制类型转换,但本质还是操作基类里那个未初始化的无效地址。类型转换只能改变编译器对指针类型的认知,无法把野指针变成有效指针,因此调用成员函数依然会访问非法内存,导致崩溃。
修复方案
解决核心是让基类和派生类共用同一个toyInteractor变量,不要隐藏:
- 删除派生类
Horse和Bird中重新声明的ToyInteractor *toyInteractor = ...;; - 在派生类构造函数中给基类的
toyInteractor赋值:
class Horse : public Toy { public: Horse() { toyInteractor = new HorseInteractor(); }; ~Horse() {}; void func() override { cout << "We made it inside Horse!" << endl; }; }; class Bird : public Toy { public: Bird() { toyInteractor = new BirdInteractor(); }; ~Bird() {}; void func() override { cout << "We made it inside Bird!" << endl; }; };
这样Toy* someToy访问的toyInteractor就是派生类构造时初始化的有效指针,调用interFunc()就能正常执行。
内容的提问来源于stack exchange,提问作者LimeAndConconut
相关产品推荐
相关产品推荐

