一个指向组合接口的指针——指向实现其中一个接口并扩展另一个接口实现的类。

4

我有两个接口:

class FirstInterface
{
    virtual int getId() const = 0;
};

class SecondInterface
{
    virtual void setId(int id) = 0;
};

这是一个综合界面:
class CombinedInterface : public FirstInterface, public SecondInterface
{

};

这是第一个接口的具体类:

class FirstConcrete : public FirstInterface
{
    virtual int getId() const
    {
        return 1;
    }
};

现在,这个类 CompleteConcrete 应该具有 CombinedInterface,但同时希望重用 FirstConcrete 的实现。
class CompleteConcrete : public FirstConcrete, public SecondInterface
{
    virtual void setId(int id) { }
};

// This is wrong C++
// Cannot convert from CompleteConcrete * to CombinedInterface *
// CombinedInterface * combinedInterface = new CompleteConcrete();

当然,这是不起作用的。有人知道在C++中实现这个目标的方法吗?

你真的需要 CombinedInterface 吗? - Jarod42
1
您可以使用组合来重用实现。 - Jarod42
@SamVarshavchik 我知道什么是虚拟继承,虽然我不太喜欢使用这种技术,但如果它能够达到目标且没有严重的副作用,我会使用它。请发表您的答案。 - Meena Alfons
@Jarod42 组合需要实现所有 FirstInterface 方法并将它们委托给类型为 FirstConcrete 的成员变量,对吧?但这不会暴露 FirstConcrete 的受保护成员,其中可能包括缓存,并且访问它们会很有帮助。 - Meena Alfons
我认为如果每个人都发布他们的答案会很好。 - Meena Alfons
显示剩余5条评论
2个回答

1
以下是我在评论中提到的基于虚拟继承的解决方案:
class FirstInterface
{
    virtual int getId() const = 0;
};

class SecondInterface
{
    virtual void setId(int id) = 0;
};


class CombinedInterface : virtual public FirstInterface,
              virtual public SecondInterface
{

};

class FirstConcrete : virtual public FirstInterface
{
    virtual int getId() const
    {
        return 1;
    }
};

class CompleteConcrete : virtual public FirstConcrete,
             virtual public CombinedInterface
{
    virtual void setId(int id) { }
};

void example()
{
    CombinedInterface * combinedInterface = new CompleteConcrete();
}

使用虚拟继承时,除了“大象在屋子里”的问题之外,唯一需要的更改是让CompleteConcreteCombinedInterface中多重继承,而不是从SecondInterface中继承。可以这样考虑:有了CompleteConcreate,它现在支持CombinedInterface,而不仅仅是增加了SecondInterface

有些人对虚拟继承表示不满,但我不这样认为。虚拟继承是C++的独特功能之一,在我所知的其他高级语言中没有共享。它是一个非常强大的工具,可以解决其他方法难以解决的某些问题。虚拟继承的两个主要缺点是:

  1. 因为它非常强大,很容易被滥用,导致各种问题。

  2. 如果虚拟继承的类具有非默认构造函数,则很快就会变得棘手,因为现在每个虚拟继承某些东西的类都负责构建它。

但是只要正确使用虚拟继承,并且涉及的类能够构建自己,虚拟继承就是一个有用的工具。

顺便提一下,我还想提供另一种解决方案。如果你的CombinedInterface只是为了某个特定函数而被引用,比如:

 void somefunction(CombinedInterface &object);

你的函数需要一个组合接口。
做出小的更改:
 void somefunction(FirstInterface &first, SecondInterface &second);

传递同一对象作为两个参数。可以传递实现两个接口的 CompleteConcrete,而无需更改类层次结构。您也可以拥有一个模板外观,使其看起来像函数仍然只需要一个参数:

template<typename T> void somefunction(T &&t)
{
    real_somefunction(std::forward<T>(t), std::forward<T>(t));
}

void real_somefunction(FirstInterface &first, SecondInterface &second);

你可以基本上摆脱CombinedInterface,并且简单地将任何实现这两个接口的对象传递给somefunction(),你的real_somefunction()将使用其中一个参数来调用适当的接口。假设你需要携带指向同时实现这两个接口的对象的指针?
class combined_pointer : public std::pair<FirstInterface *, SecondInterface *> {

public:
    template<typename T> combined_pointer(T *t)
            : std::pair<FirstInterface *, SecondInterface *>(t, t)
    {}
};

只是一个起点。


很好的解释和介绍其他解决方案。我需要告诉你为什么我真正需要CombinedInterface。我正在实现一个工厂,它返回指向CombinedInterface的指针。这就是为什么玩弄两个接口的技巧行不通的原因。 - Meena Alfons

0

我已经使用了虚拟继承。

这个编译成功了,但是有一个警告,不过我认为没问题。

class FirstInterface
{
    virtual int getId() const = 0;
};

class SecondInterface
{
    virtual void setId(int id) = 0;
};

class CombinedInterface : virtual public FirstInterface, public SecondInterface
{

};

class FirstConcrete : virtual public FirstInterface
{
    virtual int getId() const
    {
        return 1;
    }
};


class CompleteConcrete : public CombinedInterface, public FirstConcrete
{
    virtual void setId(int id) { }
};


// warning: C4250:  inherits via dominance
CombinedInterface * combinedInterface = new CompleteConcrete();

可以的。你可以永久性地抑制C4250警告。你想要通过支配实现继承。我不知道为什么微软编译器开发人员认为这是一件坏事。 - n. m.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接