C ++组成与抽象类 [英] C++ Composition with abstract class
问题描述
让我们说我有一个抽象类,它的创建和复制非常昂贵:
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";
}
};
此外,我想创建一个使用FirstDerived
或SecondDerived
通过组合(而不是聚合)的类.这意味着我希望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
.
有人知道这里发生了什么吗?为什么创建ComposedOfFirstDerived
比ComposedOfAbstractBase
这么快?有没有更好的方法来对抽象类进行合成,还是我陷入了次优的解决方案?
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屋!