C ++组成与抽象类 [英] C++ Composition with abstract class

查看:124
本文介绍了C ++组成与抽象类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说我有一个抽象类,它的创建和复制非常昂贵:

Lets say I have an abstract class that is expensive to create and copy:

class AbstractBase {
public:
    AbstractBase() {
        for (int i = 0; i < 50000000; ++i) {
            values.push_back(i);
        }
    }

    virtual void doThing() = 0;

private:
    vector<int> values;
};

它有两个子类:

It has two subclasses FirstDerived:

class FirstDerived : public AbstractBase {
public:
    void doThing() {
        std::cout << "I did the thing in FirstDerived!\n";
    }

};

SecondDerived:

class SecondDerived : public AbstractBase {
public:
    void doThing() {
        std::cout << "I did the thing in SecondDerived!\n";
    }
};

此外,我想创建一个使用FirstDerivedSecondDerived通过组合(而不是聚合)的类.这意味着我希望ComposedOfAbstractBase成为 own 所传入的任何临时对象.如果我不在此类中使用抽象类,则该类看起来像:(在C ++ 11中)

Further, I would like to make a class that utilizes FirstDerived or SecondDerived using composition (not aggregation). Meaning that I want ComposedOfAbstractBase to own whichever temporary is passed in. If I weren't using abstract classes in this class would look like: (in C++11)

class ComposedOfWhicheverDerived {
public:
    ComposedOfWhicheverDerived(AbstractBase abstract_base) : abstract_base(std::move(abstract_base)) {;}
private:
    AbstractBase abstract_base;
};

但是,这不适用于抽象类,因为即使我小心不要传递临时的AbstractBase,我也无法创建AbstractBase的实例,就像这样:

However, this does not work with abstract classes because I cannot ever create an instance of AbstractBase, even if I am careful about not passing in a temporary AbstractBase, like so:

ComposedOfWhicheverDerived a(FirstDerived());

对于编译器而言,这与以下情况一样糟糕:

To the compiler this is just as bad as:

ComposedOfWhicheverDerived b(AbstractBase());

因为在类声明中我仍然有AbstractBase的实例.

Because I still have an instance of AbstractBase in the class declaration.

我想到的下一个解决方案是:

The next solution I came up with is:

class ComposedOfAbstractBase {
public:
    ComposedOfAbstractBase(AbstractBase&& abstract_base) : some_derived_instance(abstract_base) {;}

private:
    AbstractBase& some_derived_instance;
};

这很完美(即使我不太了解)!这两个实例都是有效的,并且可以按预期工作:

This works perfectly (even though I don't fully understand it)! Both of these instances are valid and work as intended:

ComposedOfAbstractBase a(FirstDerived());
ComposedOfAbstractBase b(SecondDerived());

它不会为传入的任何AbstractBase临时文件创建副本,并且允许存储对AbstractBase的引用.尽管充其量对一个右值引用的引用似乎还不清楚:它并不能传达ComposedOfAbstractBase owns 传递给哪个临时对象.此外,事实证明,该解决方案似乎是不合时宜的.最佳的.为了显示这一点,我创建了此类:

It doesn't create a copy of whatever AbstractBase temporary is passed in, and storing a reference to an AbstractBase is allowed. Though at best the reference to an rvalue reference seems unclear: it does not convey that ComposedOfAbstractBase owns whichever temporary is passed in. In addition to that, it turns out that this solution seems to be sub-optimal. To show this I created this class:

class ComposedOfFirstDerived {
public:
    ComposedOfFirstDerived(FirstDerived first_derived) : first_derived(std::move(first_derived)) {;}

private:
    FirstDerived first_derived;
};

只能接受一个FirstDerived,因此我们可以应用std::move来卸载该临时文件的所有权.我可以这样创建一个实例:

Which can only take in a FirstDerived, so we can apply the std::move to offload ownership of the temporary. I can make an instance like so:

ComposedOfFirstDerived c(FirstDerived()); 

足够有趣的是,此类始终比ComposedOfAbstractClass快10%.

Interestingly enough, this class consistently is 10% faster to create than ComposedOfAbstractClass.

有人知道这里发生了什么吗?为什么创建ComposedOfFirstDerivedComposedOfAbstractBase这么快?有没有更好的方法来对抽象类进行合成,还是我陷入了次优的解决方案?

Does anybody know what is going on here? Why is ComposedOfFirstDerived so much faster to create than ComposedOfAbstractBase? Is there a better way to do composition with abstract classes or am I stuck with a sub-optimal solution?

很抱歉,如果这是一个问题.感谢所有花时间阅读它并给出真实答案的人,因为我感到很困惑!

Sorry if this was a mouthful of a question. I appreciate anyone who takes the time to read through it and give a genuine answer, because I am beyond stumped!

推荐答案

ComposedOfAbstractBase不是解决方案.您正在悬挂参考.

ComposedOfAbstractBase is not a solution. You're holding a dangling reference.

由于顾名思义,AbstractBase是抽象的-您不能按值保存一个.您只能按引用或指针保存一个.由于引用不能拥有该对象,因此将剩下指针.拥有指针的现代方式是使用unique_ptr:

Since AbstractBase is, as the name suggests, abstract - you cannot hold one by value. You can only hold one by reference or by pointer. Since a reference cannot own the object, that leaves you with the pointer. And the modern way of owning a pointer is to use unique_ptr:

class ComposedOfAbstractBasePtr {
public:
    ComposedOfAbstractBasePtr(std::unique_ptr<AbstractBase> p)
    : some_derived_instance(std::move(p))
    { }

private:
    std::unique_ptr<AbstractBase> some_derived_instance;
};

请注意,您的AbstractBase没有虚拟析构函数.你应该解决这个问题.

Note that your AbstractBase does not have a virtual destructor. You should fix that.

这篇关于C ++组成与抽象类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆