C++通过父类list指针调用子类重载运算符实现运行时多态
问题修复方案
问题根因
代码无法触发运行时多态的核心原因有两个:
- 运算符调用语法错误:
p + (rand() % 100)是对list*类型的指针做地址算术运算,根本没有调用对象的成员运算符函数,完全不会进入虚函数分发逻辑。 - 虚函数返回值设计缺陷:
operator+定义为返回list值类型,子类重写时返回的实例会被切割为基类对象,发生对象切片,破坏多态一致性。
修复要点
- 修正
operator+的调用逻辑:对指针解引用后再触发运算符调用,将原代码中p + (rand() % 100)替换为(*p) + (rand() % 100)。 - 调整
operator+的返回值类型:将基类和子类中该运算符的返回值从list值类型修改为list&引用类型,避免对象切片,保证虚函数重写的合法性。
修复后完整代码
#include <iostream> #include <cstdlib> #include <time.h> #include <cctype> using namespace std; class list { public: list* head; list* tail; list* next; int num; virtual ~list() {} list() { head = tail = next = NULL; num = 0; } // 修改返回值为引用类型 virtual list& operator+(int i) { return *this; }; virtual int operator-() { return 0; }; }; class queue : public list { public: // 同步修改返回值为引用类型,符合虚函数重写规则 list& operator+(int i) override; int operator-() override; }; class stack : public list { public: list& operator+(int i) override; int operator-() override; }; int main() { srand(time(NULL)); rand(); list* p; queue q_ob; stack s_ob; char ch; for (;;) { cout << "Enter something else to stop.\nStack, Queue or ULL? (S/Q): \n"; cin >> ch; ch = tolower(ch); if (ch == 'q') p = &q_ob; else if (ch == 's') p = &s_ob; else break; // 修正:解引用指针后调用运算符 (*p) + (rand() % 100); } cout << "Enter T to terminate\n"; for (;;) { cout << "Remove from Stack, Queue or ULL? (S/Q):"; cin >> ch; ch = tolower(ch); if (ch == 'q') p = &q_ob; else if (ch == 's') p = &s_ob; else break; cout << -(*p) << '\n'; } return 0; } list& queue::operator+(int i) { list* item; item = new queue; if (!item) { cout << "Allocation error.\n"; exit(1); } item->num = i; // 队列元素追加到尾部 if (tail) tail->next = item; tail = item; item->next = NULL; if (!head) head = tail; return *this; } int queue::operator-() { int i; list* p; if (!head) { cout << "List empty.\n"; return 0; } // 队列从头部取出元素 i = head->num; p = head; head = head->next; delete p; return i; } list& stack::operator+(int i) { list* item; item = new stack; if (!item) { cout << "Allocation error.\n"; exit(1); } item->num = i; // 栈元素插入到头部 if (head) item->next = head; head = item; if (!tail) tail = head; return *this; } int stack::operator-() { int i; list* p; if (!head) { cout << "List empty.\n"; return 0; } // 栈从头部取出元素 i = head->num; p = head; head = head->next; delete p; return i; }
补充说明:代码中添加了
override关键字显式标记虚函数重写,可以在编译阶段检查重写合法性,避免签名不匹配导致的重写失效问题;补充了<cctype>头文件引入tolower函数声明,避免部分编译环境下的隐式声明警告。
内容的提问来源于stack exchange,提问作者nameses
相关产品推荐
相关产品推荐

