派生类同名成员变量未覆盖基类?C++代码行为疑问
为什么派生类同名成员不会让基类函数调用到派生类的成员?
你的代码运行后打印from foo而非from override foo,核心原因是派生类的m_data并没有覆盖基类的m_data,而是定义了一个同名的独立成员,属于C++的「名字隐藏」规则,具体拆解如下:
1. 内存中的两个独立成员
基类Base和派生类Derived的m_data是完全分开的两个成员,在对象内存布局中同时存在:
- 基类
Base自带一个Foo* m_data,初始化指向Foo对象; - 派生类
Derived额外定义了一个t* m_data(这里t是OverrideFoo),初始化指向OverrideFoo对象。
2. 成员函数的作用域规则
基类的useData()函数属于Base类的作用域,它里面的m_data只会绑定到Base类自己的成员,和派生类的同名成员毫无关系。哪怕你通过派生类对象调用useData(),函数的执行逻辑仍然遵循基类的作用域,只会访问基类的Foo* m_data,所以打印from foo。
反过来,如果在派生类中定义自己的成员函数:
template <class t> struct Derived : public Base { t* m_data {new t()}; void printDerived() { m_data->print(); // 这里访问的是派生类的m_data,会打印"from override foo" } };
调用d.printDerived()就会得到你预期的结果,因为这个函数属于派生类作用域,优先访问派生类的同名成员。
3. 非模板场景的验证
这种行为和模板无关,普通派生类也会出现相同情况:
struct Derived : public Base { OverrideFoo* m_data {new OverrideFoo()}; };
此时调用Derived对象的useData(),依然会打印from foo,原因和上面完全一致。
如何让基类函数使用派生类成员?
如果想让基类的useData()能调用到派生类的成员,需要用多态或者**模板继承(CRTP)**的方式:
- 多态方案:让
Foo和OverrideFoo继承自同一个基类,把print()定义为虚函数,基类Base的m_data改为基类指针; - CRTP方案:让基类依赖派生类类型,直接访问派生类的成员。
比如多态的实现示例:
struct BaseFoo { virtual void print() = 0; virtual ~BaseFoo() = default; }; struct Foo : BaseFoo { void print() override { printf("from foo\n"); } }; struct OverrideFoo : BaseFoo { void print() override { printf("from override foo\n"); } }; struct Base { virtual BaseFoo* getData() { return m_data; } void useData() { getData()->print(); } Foo* m_data {new Foo()}; }; template <class t> struct Derived : public Base { t* m_data {new t()}; BaseFoo* getData() override { return m_data; } };
这时调用d.useData()就会打印from override foo。
内容的提问来源于stack exchange,提问作者pepero
相关产品推荐
相关产品推荐

