You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何此处virtual未调用重写函数?如何修正该问题?

问题分析与解决方案

问题根源

你代码里的核心问题是成员变量没有多态特性:

  • B类中的MemB* current只是隐藏了A类的MemA* current,但A类的getMemClass()成员函数只会访问自身类作用域内的current指针,也就是A构造函数中创建的MemA实例,所以输出的是MemA的内容。
  • 虚函数的多态是针对成员函数的,成员变量不存在运行时动态绑定的机制,同名变量只会发生作用域隐藏。

可行解决方案

方案1:将getMemClass声明为虚函数,在B中重写

把A类的getMemClass改成虚函数,然后在B类中重写这个方法,让它访问B自己的current指针:

#include <iostream>
struct MemA { virtual void tellClass() { std::cout << "I am member of class A" << std::endl; } };
struct MemB : public MemA { void tellClass() { std::cout << "I am member of class B" << std::endl; } };

class A {
    MemA *current;
public:
    A() : current(new MemA()) {}
    // 声明为虚函数
    virtual void getMemClass() { current->tellClass(); }
    virtual ~A() { delete current; } // 基类析构设为虚,避免内存泄漏
};
class B : public A {
    MemB *current;
public:
    B() : A(), current(new MemB()) {}
    // 重写getMemClass,访问B自己的current
    void getMemClass() override { current->tellClass(); }
    ~B() { delete current; }
};

int main() { B().getMemClass(); } // 标准C++中main返回类型必须是int

调用B对象的getMemClass()时,会触发虚函数动态绑定,执行B类的重写版本,输出I am member of class B。

方案2:复用A类的current指针,避免重复定义

既然MemB是MemA的子类,完全可以让A类的current指针指向MemB实例,不需要在B类中重新定义current:

#include <iostream>
struct MemA { virtual void tellClass() { std::cout << "I am member of class A" << std::endl; } };
struct MemB : public MemA { void tellClass() { std::cout << "I am member of class B" << std::endl; } };

class A {
protected: // 改为protected,让子类可以访问
    MemA *current;
public:
    A() : current(new MemA()) {}
    void getMemClass() { current->tellClass(); }
    virtual ~A() { delete current; } // 基类析构设为虚
};
class B : public A {
public:
    B() : A() {
        // 先删除A构造的MemA实例,再替换为MemB
        delete current;
        current = new MemB();
    }
};

int main() { B().getMemClass(); }

这种方案利用MemA和MemB的多态性,让A类的current指向MemB对象,调用tellClass()时自动触发动态绑定,输出目标内容。

方案3:使用工厂方法模式(更优雅的设计)

如果后续还有更多MemA的子类,可以给A类添加一个虚的工厂方法,用来创建MemA实例,子类重写这个方法返回对应子类的实例:

#include <iostream>
struct MemA { virtual void tellClass() { std::cout << "I am member of class A" << std::endl; } };
struct MemB : public MemA { void tellClass() { std::cout << "I am member of class B" << std::endl; } };

class A {
    MemA *current;
    // 虚工厂方法,子类重写
    virtual MemA* createMem() {
        return new MemA();
    }
public:
    A() : current(createMem()) {}
    void getMemClass() { current->tellClass(); }
    virtual ~A() { delete current; }
};
class B : public A {
    MemB* createMem() override {
        return new MemB();
    }
};

int main() { B().getMemClass(); }

这种设计符合开闭原则,新增子类时不需要修改A类的逻辑,只需要重写createMem()方法即可。

额外注意点

  • 标准C++中main函数的返回类型必须是int,不能是void,这是编译器的标准要求。
  • 基类的析构函数必须声明为虚函数,否则当通过基类指针删除子类对象时,会导致子类的析构函数不被调用,引发内存泄漏。

内容的提问来源于stack exchange,提问作者Chandramouli Mukherjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:00:57