C++继承场景下no viable overloaded '='报错及多态失效问题
问题原因
- 最初的编译报错是因为
p1是栈上分配的Player类型实例,而new HumanPlayer()返回的是HumanPlayer类型的指针,二者类型不匹配无法直接赋值,将p1改为Player*指针类型的修改方向是正确的。 - 改指针后多态不生效的核心原因是:C++要实现运行时多态,必须将基类中需要被子类重写的成员函数声明为
virtual虚函数。当前代码中的getMove方法没有virtual修饰,编译器会执行静态绑定,直接根据指针的静态类型Player*调用父类的getMove实现,不会匹配子类的重写方法。
解决方法
- 给基类
Player的getMove方法添加virtual修饰符,C++11及更高版本还可以在子类重写的方法后加override关键字,显式标记该方法是重写父类的方法,避免因函数签名写错导致重写失效的问题。 - 基类声明了虚函数后,最好同时声明虚析构函数,避免后续通过基类指针释放子类对象时,只调用基类析构函数造成内存泄漏。
- 注意手动管理堆内存的释放,或者使用
std::unique_ptr等智能指针自动管理内存,避免内存泄漏。
修正后的完整代码
#include <iostream> using namespace std; class Player { public: // 声明为虚函数 virtual void getMove(int player) { cout << "Get move" << endl; } // 虚析构函数保证子类析构被正常调用 virtual ~Player() = default; }; class HumanPlayer: public Player { public: // override显式标记重写,编译期会校验重写合法性 void getMove(int player) override { cout << "Get Human move \n"; } }; class MyClass { public: int mode; Player* p1; MyClass() { p1 = nullptr; mode = 0; cout << "Choose a mode: \n"; cin >> mode; switch (mode) { case 1: p1 = new HumanPlayer(); break; default: p1 = new Player(); break; } p1->getMove(0); } // 析构函数释放堆内存避免泄漏 ~MyClass() { delete p1; } }; int main() { MyClass c; return 0; }
内容的提问来源于stack exchange,提问作者Amy Cohen
相关产品推荐
相关产品推荐

