简体   繁体   English

在容器中存储多继承对象

[英]Storing multiple-inheritance objects in container

A library I use has many types, all of which derive from the same 2 interfaces: 我使用的库有很多类型,所有类型都来自相同的2个接口:

class Huey : public IDuck, public ICartoonCharacter
{
...
};

class Dewey : public IDuck, public ICartoonCharacter
{
...
};

class Louie : public IDuck, public ICartoonCharacter
{
...
};

I'd like to store objects of all the above types in a wrapper class and stick objects of that wrapper class in a container. 我想将所有上述类型的对象存储在包装类中,并将该包装类的对象粘贴到容器中。 Of course I should be able to call methods belonging to both interfaces from my wrapper class. 当然,我应该能够从我的包装类中调用属于这两个接口的方法。

What are my options here? 我有什么选择? I could think of 我能想到

  • storing IDuck * s in my wrapper and dynamic_cast-ing to ICartoonCharacter , or IDuck *存储在我的包装器中,并将dynamic_cast-ing存储到ICartoonCharacter ,或者
  • using something like boost::any while making my wrapper a class-template, with a couple of static_asserts to ensure the template parameter inherits from IDuck and ICartoonCharacter . 使用boost::any类的东西,同时使我的包装器成为一个类模板,带有几个static_asserts以确保模板参数继承自IDuckICartoonCharacter

but neither option particularly appeals. 但两种选择都没有特别吸引人。 Any ideas? 有任何想法吗?

two interfaces, multiple inheritance combine into one container? 两个接口,多个继承组合成一个容器? is a related question, but James Kanze's answer doesn't work for me, as I can't change the 3 classes. 是一个相关的问题,但詹姆斯坎泽的答案对我不起作用,因为我不能改变3个班级。

EDIT: Don't use multiple inheritance often, had forgotten syntax. 编辑:不要经常使用多重继承,忘记了语法。 Now inheriting public ly from both interfaces. 现在从两个接口继承public ly。

EDIT: Now using dynamic_cast instead of static_cast (which won't work). 编辑:现在使用dynamic_cast而不是static_cast(这将无法工作)。

EDIT: I found both Mike Seymour's and Matthieu M's answers promising. 编辑:我发现Mike Seymour和Matthieu M的答案都很有希望。 I'll accept one of their answers once I've coded it all up. 一旦我编码完毕,我会接受他们的一个答案。 Thanks! 谢谢!

A simple option is to store two pointers in the wrapper: 一个简单的选择是在包装器中存储两个指针:

struct CartoonDuckWrapper {
    IDuck * duck;
    ICartoonCharacter * toon;

    template <class CartoonDuck>
    CartoonDuckWrapper(CartoonDuck & cd) : duck(&cd), toon(&cd) {}
};

There's no particular need to use static_assert to check that CartoonDuck inherits from both base classes, although that might give slightly better diagnostics than simply letting the pointer conversions fail. 没有特别需要使用static_assert来检查CartoonDuck从两个基类继承,尽管这可能比仅仅让指针转换失败提供更好的诊断。

If the base classes are polymorphic (which, being interfaces, they probably are), you could save the space of one pointer, in exchange for a run-time cost, by using dynamic_cast to convert one to the other. 如果基类是多态的(可能是接口,它们可能是接口),则可以通过使用dynamic_cast将一个指针转换为另一个来节省一个指针的空间,以换取运行时成本。 static_cast can't be used for such a "cross-cast" between base classes. static_cast不能用于基类之间的这种“交叉投射”。

As all issues in programming, you can solve it by adding one more level of indirection. 作为编程中的所有问题,您可以通过添加一个更多级别的间接来解决它。

class ICartoonDuck: public IDuck, public ICartoonCharacter {};

template <typename T>
class CartoonDuck: public ICartoonDuck {
public:
    explicit CartoonDuck(T t): _t(std::move(t)) {}

    // IDuck interface
    virtual void foo() override { t.foo(); }

    // ICartoonCharacter interface
    virtual void bar() override { t.bar(); }

private:
    T _t; // or any ownership scheme that makes sense
}; // class CartoonDuck

template <typename T>
CartoonDuck<T> makeCartoonDuck(T t) { return CartoonDuck(std::move(t)); }

template <typename T, typename... Args>
std::unique_ptr<CartoonDuck<T>> makeUniqueCartoonDuck(Args&&...) {
    return std::unique_ptr<CartoonDuck<T>>(new T(std::forward<Args>()...);
}

Now, you can happily store std::unique_ptr<ICartoonDuck> in your container. 现在,您可以愉快地将std::unique_ptr<ICartoonDuck>存储在容器中。

This can be used as: 这可以用作:

std::vector<std::unique_ptr<ICartoonDuck>> cartoonDucks;
cartoonDucks.push_back(makeUniqueCartoonDuck<Huey>());
cartoonDucks.push_back(makeUniqueCartoonDuck<Dewey>());
cartoonDucks.push_back(makeUniqueCartoonDuck<Louie>());

for (std::unique_ptr<ICartoonDuck> const& cd: cartoonDucks) {
    cd->foo();
    cd->bar();
}

Create an intermediate class: 创建一个中间类:

class ILuckyDuck: public IDuck, ICartoonCharacter //...

with: 有:

class Huey : public ILuckyDuck //...

etc , and store: ,并存储:

std::vector<std:shared_ptr<ILuckyDuck>> donald;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM