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

C++:如何通过继承成员函数重写接口以消除抽象类

解决C++多重继承下接口方法未被基类实现覆盖的问题

你的问题核心在于菱形继承导致的重复基类实例,使得Select类无法复用From的leftJoin实现来满足ISelect继承链中的纯虚函数要求。

问题根源

你的类继承结构是:

  • IFrom是顶层纯虚接口,包含纯虚leftJoin
  • ISelect继承IFrom,新增纯虚from
  • From继承IFrom,实现leftJoin
  • Select同时继承ISelect和From

这种结构会让Select内部存在两个独立的IFrom子对象:一个来自ISelect的继承链,另一个来自From的继承链。From实现的leftJoin只覆盖了它自己继承的那个IFrom的纯虚函数,而ISelect继承的IFrom的leftJoin仍然是未实现的纯虚函数,所以Select被判定为抽象类,无法实例化。

解决方案:使用虚继承消除重复基类

通过虚继承让所有继承IFrom的子类共享同一个IFrom基类实例,这样From的leftJoin实现就能覆盖唯一的IFrom纯虚函数,同时Select实现ISelect的from方法后,就不再是抽象类。

修改后的代码如下:

1. 修改接口类的继承方式

// 顶层IFrom接口保持不变
class IFrom
{
public:
    virtual ~IFrom() = 0;
    virtual std::unique_ptr<IFrom> leftJoin(
        const IEntityAlias &entity_alias,
        const IColumnName &lhs_column_name,
        const IComparisonOperator &comp_operator,
        const IColumnName &rhs_column_name) = 0;
};

inline IFrom::~IFrom() {}

// ISelect改为虚继承IFrom
class ISelect : public virtual IFrom
{
public:
    virtual ~ISelect() = 0;
    virtual std::unique_ptr<IFrom> from(const IEntityAlias &entity_alias) = 0;
};

inline ISelect::~ISelect() {}

2. 修改实现类的继承方式(并修正笔误)

// From改为虚继承IFrom,同时修正构造函数的笔误(原代码中的Form是拼写错误)
class From: public virtual IFrom
{
protected:
    std::shared_ptr<PostgreSQL> _SGBDR;
    std::string _current_query;

public:
    From() = default;
    From(const std::shared_ptr<PostgreSQL> SGBDR, std::string &&current_query);
    From(From &&o); // 修正原代码的Form为From
    From(const From &o) = delete;
    const From &operator=(const From &o) = delete;
    virtual ~From() = default;

    std::unique_ptr<IFrom> leftJoin(
        const IEntityAlias &entity_alias,
        const IColumnName &lhs_column_name,
        const IComparisonOperator &comp_operator,
        const IColumnName &rhs_column_name) override;
};

// Select类无需修改继承方式,因为父类都已使用虚继承
class Select : public ISelect, public From
{
public:
    using From::From;
    using From::leftJoin;

    std::unique_ptr<IFrom> from(const IEntityAlias &entity_alias) override;
};

验证你的预期调用

现在Select可以正常实例化,且满足你的调用需求:

// 正常实例化Select
ISelect *select = new Select();
select->from(/* 传入对应参数 */);
select->from(/* 传入对应参数 */)->leftJoin(/* 传入对应参数 */);
select->leftJoin(/* 传入对应参数 */); // 注意方法名是leftJoin,和定义保持大小写一致

IFrom *from = new From(/* 传入对应参数 */);
from->leftJoin(/* 传入对应参数 */);
// from->from(); // 编译报错,符合预期,IFrom没有from方法

额外说明

虚继承会在对象中添加额外的虚基类指针,带来微小的性能开销,但对于ORM这种场景来说完全可以忽略。它解决了菱形继承中重复基类的问题,是C++中处理这类多接口继承场景的标准方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 22:15:08