C++父类指针数组存子类实例,调用printall异常,求错误原因
你遇到的问题核心是数组的传递和访问方式错误,加上可能缺少虚函数的定义,导致内存访问越界或者调用了错误的函数版本。咱们一步步拆解:
先看你代码里的关键问题点
首先是你的printall方法调用和实现:
// 调用时传了*CA p.printall(*CA, (size)); // printall的实现 void Print::printall(CompressionAlgorithm *ca, int size) { for (int i = 0; i < size; i++) { cout << i+1 << " for "; cout << ca[i].GetName(); // 这里用了.访问,而ca[i]是错误的对象 cout << "\n"; } }
你定义的CA是CompressionAlgorithm *CA[size],也就是一个指针数组,每个元素是指向子类对象的父类指针。但你调用printall时传了*CA,这等价于传了CA[0]——也就是第一个子类对象的指针。
然后在printall里,ca[i]会被编译器解释为:从ca的地址开始,偏移i * sizeof(CompressionAlgorithm)字节的位置,把那块内存当作一个CompressionAlgorithm对象。但实际上,你的数组里存的是指针(每个指针占8字节,64位系统),不是对象本身!这样ca[1]就会访问到CA[0]指向的对象内存后面的区域,完全不是CA[1]的地址,自然会触发内存访问错误(比如std::bad_alloc)或者无输出。
另外还有一个潜在问题:如果父类CompressionAlgorithm的GetName不是虚函数,那么即使你访问到了正确的对象,也会调用父类的GetName(如果父类有实现),而不是子类的版本。
正确的解决步骤
确保父类的
GetName是虚函数,并且添加虚析构
这是多态的基础,必须让父类的成员函数成为虚函数,才能通过父类指针调用子类的实现。同时虚析构能避免内存泄漏:class CompressionAlgorithm { public: // 纯虚函数,强制子类实现GetName virtual std::string GetName() const = 0; // 虚析构,确保删除子类对象时正确调用析构函数 virtual ~CompressionAlgorithm() = default; };修改
printall的参数和访问方式
我们需要接收指针数组(也就是CompressionAlgorithm**类型),然后用->访问成员函数,因为数组元素是指针:void Print::printall(CompressionAlgorithm** ca, int size) { for (int i = 0; i < size; i++) { cout << i+1 << " for "; cout << ca[i]->GetName(); // 用->访问指针指向的对象的成员 cout << "\n"; } }修改调用方式
直接传数组名CA即可,因为数组名会退化为指向第一个元素的指针(也就是CompressionAlgorithm**类型):Print p; p.printall(CA, size);
为什么这样能解决问题?
- 传
CA而不是*CA,让printall拿到的是指针数组的首地址,ca[i]就能正确访问到第i个指向子类对象的指针。 - 用
->访问成员函数,加上父类的虚函数定义,就能触发多态,正确调用子类的GetName实现。 - 虚析构保证后续用
delete CA[i]时,能正确释放子类对象的内存。
内容的提问来源于stack exchange,提问作者Kartin Palacinka

