描述从多个接口派生的对象

Describing an object that derives from multiple interfaces

本文关键字:派生 对象 接口 描述      更新时间:2023-10-16

在C++中,我有两个纯抽象类(Viewable和Movable),可能有许多类型从其中一个或两个接口派生(Dog、Duck、Cat)。

我想定义一个接受单个参数的函数,其中该参数实现两个接口。据我所知,在C++中,一个对象只能有一个静态类,所以我正在尝试想出不同的方法来解决这个问题。

下面的方法go1采用Viewable和Movable两个参数。如果我有一个类似Dog的类型,它派生了两个接口,那么我可以调用go1(d, d)。但是,我想防止go1(d, c),其中cd是不同的对象(可能具有不同的类)。

我可以创建一个从Movable和Viewable派生的新类型MovableAndViwable,但这需要我将类的定义更改为从MovableAndViwable派生,而不是从两个单独的接口派生。此外,如果我有很多接口,并且想将这个想法扩展到两种以上的类型,我最终会得到很多"混合"类型(例如,MovableAndViewableAndSavableAndRunnableAndRestorable…)

所以我的问题是:是否有银弹来解决我所描述的问题。请参阅我的示例代码中的方法go3——我想用一种方法向编译器描述一个对象从两个或多个不同且不相关的C++类派生而来。

此外,我对我的类的其他设计感兴趣,现在想知道除了C++之外的其他语言如何解决这个问题(假设我不需要使用C++)。

#include <iostream>
struct Movable { virtual void move() const = 0; };
struct Viewable { virtual void view() const = 0; };
struct MovableAndViewable : Movable, Viewable {};
struct Dog : virtual Movable, virtual Viewable {
    void move() const { std::cout << "Movingn"; }
    void view() const { std::cout << "Viewingn"; }
};
struct Duck : virtual Movable, virtual Viewable {
    void move() const { std::cout << "Movingn"; }
    void view() const { std::cout << "Viewingn"; }
};
struct Cat : virtual MovableAndViewable {
    void move() const { std::cout << "Movingn"; }
    void view() const { std::cout << "Viewingn"; }
};
struct Fish : virtual Movable {
    void move() const { std::cout << "Movingn"; }
};
void go1(Movable const &m, Viewable const &v) { m.move(); v.view(); }
void go2(MovableAndViewable const &mv) { mv.move(); mv.view(); }
//void go3(Movable and Viewable const &mv) { mv.move(); mv.view(); }
int main()
{
    Dog d;
    Cat c;
    Fish f;
    go1(d, d);
    //go1(f, f); // Nope, Fish isn't Viewable
    //go2(d);
    go1(c, c);
    go2(c);
    //go3(d);
    //go3(c);
    return 0;
}

下面的方法怎么样。它似乎满足了您传递单个参数的期望目标:

class Movable {
public:
    virtual void move()=0;
};
class Viewable {
public:
    virtual void view()=0;
};
// A stub class, used for parameter passing.
class MovableAndViewable {
public:
    Movable &m;
    Viewable &v;
public:
    template<typename m_and_v> MovableAndViewable(m_and_v &object)
        : m(object), v(object)
    {
    }
};
// Passing only a single parameter:    
void go2(const MovableAndViewable &mv)
{
    mv.m.move();
    mv.v.view();
}
// Example:
class MV : public Movable, public Viewable {
public:
    void move()
    {
    }
    void view()
    {
    }
};
void go3()
{
    MV mv;
    go2(mv);
}

然后,另外我还要声明:

class const_MovableAndViewable {
public:
    const Movable &m;
    const Viewable &v;
public:
    template<typename m_and_v> const_MovableAndViewable(const m_and_v &object)
        : m(object), v(object)
    {
    }
};
// In order to be able to pass references to const objects:
void const_go2(const const_MovableAndViewable &mv);

您可以使用动态铸造。这允许您访问实例继承的任何类型。

有一个更通用的基类可能会很有用,这样在设计函数时就不必在接口之间进行选择(base是一个常用的类型名称)。