首页 > 解决方案 > c++ 类设计、基类继承或外观设计模式

问题描述

我有一个愚蠢的 C++ 设计问题。有没有办法让一个类与多个类中的方法具有相同的方法名称(因此,相同的 API)?

我目前的情况是我有上课的情况

struct A
{
    void foo() { std::cout << "A::foo" << std::endl;}
    void boo() { std::cout << "A::boo" << std::endl;}
};

struct B
{
    void moo() { std::cout << "B::moo" << std::endl;}
    void goo() { std::cout << "A::goo" << std::endl;}
};
.... imagine possibly more

我真正想要的是另一个为这些功能充当接口的类。我可能会误解为一个简单接口的外观设计模式,它隐藏了上面实例化类的复杂性,但仍然使用它们相同的接口。

struct C 
{
    void foo() { ... }
    void boo() { ... }
    void moo() { ... }
    void goo() { ... }
};

对于上面显示的少量方法,通过声明结构 A 和 B 或将它们作为参数传递给结构 C 并在 C 中调用 A 和 B 的方法,这是可行的,但如果 A 有 40 个方法而 B 有 30 个方法,这是不切实际的方法。在 C 中重新声明 70 个具有相同名称的方法来调用 A 和 B 的底层方法,如果我能做得更好的话,似乎是无缘无故的。

我想到了使用基类的第二种解决方案

struct base
{
    void foo() { }
    void boo() { }

    void moo() { }
    void goo() { }
};

struct A : public base
{
    void foo() { std::cout << "A::foo" << std::endl;}
    void boo() { std::cout << "A::boo" << std::endl;}
};

struct B : public base
{
    void moo() { std::cout << "B::moo" << std::endl;}
    void goo() { std::cout << "A::goo" << std::endl;}
};

尝试使用具有所有函数定义的 shared_ptr。例如

std::shared_ptr<base> l_var;
l_var->foo();
l_var->boo();
l_var->moo();
l_var->goo();

这仍然不能完全满足我的要求,因为一半的方法是在结构 A 中定义的,而另一半是在结构 B 中。

我想知道多重继承是否可以解决问题,但在学校我听说进行多重继承是不好的做法(调试很难?)

有什么想法或建议吗?基本上,管理 struct A 和 B 更容易(等等,因为它是用于抽象目的的自己的类)。但是希望在某种包装器中以某种方式调用他们的方法的灵活性,其中这种复杂性对用户来说是隐藏的。

标签: c++c++11inheritancefacade

解决方案


I think that

Redeclaring 70 methods with the same name in C to call the underlying methods of A and B

is the right path.

It is tempting to use multiple inheritance in cases like this to avoid writing pass-through code but I think that is generally a mistake. Prefer composition over inheritance.

I would question whether your user really wants to deal with one interface with 70 methods but if that's really what you want then I don't see why it is "impractical" to write the code in C:

class C {
    A a;
    B b;
public:
    void foo() { return a.foo(); }
    void boo() { return a.boo(); }
    void moo() { return b.moo(); }
    void goo() { return b.goo(); }
    // ...
};

Live demo.

This has the advantage that you can easily change your mind in the future and replace A and B with something else without changing the interface of C.

You can hide the implementation of C further by using the PIMPL idiom or by splitting C into an abstract base class C and an implementation CImpl.


推荐阅读