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

继承场景下pImpl调用疑问:B调用A的foo()时使用哪个impl?

问题解答:调用B.foo()时会使用哪个impl?

嘿,这个问题刚好戳中了C里名字查找规则的关键点,结合《Effective C》第三版里的隐藏概念,咱们一步步理清楚:

首先明确你的场景:基类A定义了foo(),子类B继承A且没重写foo();A的foo()里会调用impl->foo(),而A和B各自有一个名为impl的成员。现在调用B.foo(),到底会用A::impl还是B::impl?

答案是:会使用A::impl,原因和名字查找的顺序直接相关,《Effective C++》里讲的规则正好能解释:

编译器在处理成员函数里的名字时,查找顺序是这样的:

  • 第一步:检查函数的局部作用域(比如A::foo()里有没有局部变量叫impl);
  • 第二步:检查包含这个函数的类的作用域(也就是A的类作用域);
  • 第三步:沿继承层次向上查找(也就是找A的基类,而不是向下找派生类B)。

当A::foo()里出现impl这个名字时,编译器在第二步就找到了A::impl,这时候查找就直接停止了——根本不会去派生类B的作用域里找同名的impl。毕竟基类A的代码在编译时,完全不知道有B这个子类存在,自然不会去“下游”的子类里找名字。

咱们用一段代码验证一下就更直观了:

#include <iostream>

struct ImplBase {
    virtual void foo() { std::cout << "A的impl的foo\n"; }
};

struct AImpl : ImplBase {
    void foo() override { std::cout << "A的impl的foo\n"; }
};

struct BImpl : ImplBase {
    void foo() override { std::cout << "B的impl的foo\n"; }
};

class A {
protected:
    ImplBase* impl = new AImpl();
public:
    void foo() { impl->foo(); }
};

class B : public A {
protected:
    ImplBase* impl = new BImpl();
};

int main() {
    B b;
    b.foo(); // 输出:A的impl的foo
    return 0;
}

运行这段代码,你会看到输出的是A的impl的foo,完全符合咱们的结论。

如果想要让B.foo()使用B::impl,那得换个思路——比如让A提供一个虚函数来返回impl,让B重写这个虚函数:

class A {
protected:
    virtual ImplBase* get_impl() { return new AImpl(); }
public:
    void foo() { get_impl()->foo(); }
};

class B : public A {
protected:
    ImplBase* get_impl() override { return new BImpl(); }
};

这样调用B.foo()时,就会调用B的get_impl(),从而使用B::impl的foo()了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:51:05