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

基类通过虚方法访问派生类成员的实现是否符合最佳实践?求常见模式

基类调用派生类虚方法的实现合理性与设计模式分析

问题背景

以下C++代码运行符合预期:基类B、C通过纯虚方法get_value(),成功访问到派生类D中声明的m_value成员变量,所有输出结果均为10。

示例代码

class A_abstract
{
protected:
  [[nodiscard]] virtual int get_value() const noexcept = 0;
};

class B: A_abstract
{
protected:
  [[nodiscard]] int get_value_B1() const noexcept { return get_value(); }
public:
  [[nodiscard]] int get_value_B2() const noexcept { return get_value(); }
};

class C: A_abstract
{
protected:
  [[nodiscard]] int get_value_C1() const noexcept { return get_value(); }
public:
  [[nodiscard]] int get_value_C2() const noexcept { return get_value(); }
};

class D: public B, public C
{
protected:
  int m_value = 10;
  [[nodiscard]] int get_value() const noexcept override { return m_value; }
public:
  [[nodiscard]] int get_value_1() const noexcept { return m_value; }
  [[nodiscard]] int get_value_2() const noexcept { return get_value(); }
  [[nodiscard]] int get_value_3() const noexcept { return get_value_B1(); }
  [[nodiscard]] int get_value_4() const noexcept { return get_value_C1(); }
  [[nodiscard]] int get_value_5() const noexcept { return get_value_B2(); }
  [[nodiscard]] int get_value_6() const noexcept { return get_value_C2(); }
};

int main(const int argc, const char** argv)
{
  D instance;

  std::cout << "get_value_1() = " << instance.get_value_1() << '\n';
  std::cout << "get_value_2() = " << instance.get_value_2() << '\n';
  std::cout << "get_value_3() = " << instance.get_value_3() << '\n';
  std::cout << "get_value_4() = " << instance.get_value_4() << '\n';
  std::cout << "get_value_5() = " << instance.get_value_5() << '\n';
  std::cout << "get_value_6() = " << instance.get_value_6() << '\n';
  std::cout << "get_value_B2() = " << instance.get_value_B2() << '\n';
  std::cout << "get_value_C2() = " << instance.get_value_C2() << '\n';
}

输出结果

get_value_1() = 10
get_value_2() = 10
get_value_3() = 10
get_value_4() = 10
get_value_5() = 10
get_value_6() = 10
get_value_B2() = 10
get_value_C2() = 10

核心问题解答

1. 该实现从最佳实践角度是否合理?

这个实现虽然能正常运行,但存在多处违背C++最佳实践的问题:

  • 菱形继承隐患:A_abstract被B、C非虚拟继承,D多重继承后会产生A_abstract的两个独立实例。即便当前A是纯虚类无成员数据,后续若给A添加变量,会直接导致数据冗余、访问歧义,维护成本陡增。
  • 依赖关系倒置违规:基类B、C的方法直接依赖派生类D对get_value()的实现,违反依赖倒置原则——高层模块不应直接依赖低层模块,二者都应依赖抽象接口。这种设计会让B、C无法脱离D独立复用,耦合度过高。
  • 接口冗余臃肿:D类中定义了大量重复逻辑的方法(get_value_1到get_value_6),外部还可直接调用B、C的public方法,既增加了代码量,又容易让使用者混淆接口意图,后期维护易出错。

2. 此类场景的常见设计模式是什么?

这种基类定义框架逻辑、派生类实现具体细节的场景,最贴合的是模板方法模式:

  • 模板方法模式的核心是在抽象基类中定义算法骨架(比如B的get_value_B1/B2就是骨架中的固定步骤),将可变的具体实现(比如获取值的逻辑)延迟到派生类中完成(D的get_value())。
  • 如果需要进一步降低耦合,也可结合依赖注入思想:让基类通过构造函数或参数接收一个提供数据的抽象对象,而非直接依赖派生类的虚方法,这种方式更灵活,也符合单一职责原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:44:55