带有抽象类的c++组合
C++ Composition with abstract class
假设我有一个抽象类,它的创建和复制成本很高:
class AbstractBase {
public:
AbstractBase() {
for (int i = 0; i < 50000000; ++i) {
values.push_back(i);
}
}
virtual void doThing() = 0;
private:
vector<int> values;
};
有两个子类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
拥有传入的。如果我没有在这个类中使用抽象类,这个类看起来像:(在c++ 11中)
class ComposedOfWhicheverDerived {
public:
ComposedOfWhicheverDerived(AbstractBase abstract_base) : abstract_base(std::move(abstract_base)) {;}
private:
AbstractBase abstract_base;
};
然而,这对抽象类不起作用,因为我不能创建AbstractBase
的实例,即使我小心地不传递临时AbstractBase
,像这样:
ComposedOfWhicheverDerived a(FirstDerived());
对于编译器来说,这和:
一样糟糕ComposedOfWhicheverDerived b(AbstractBase());
因为在类声明中仍然有一个AbstractBase
的实例。
我想到的下一个解决方案是:
class ComposedOfAbstractBase {
public:
ComposedOfAbstractBase(AbstractBase&& abstract_base) : some_derived_instance(abstract_base) {;}
private:
AbstractBase& some_derived_instance;
};
这工作完美(即使我不完全理解它)!这两个实例都是有效的,并按预期工作:
ComposedOfAbstractBase a(FirstDerived());
ComposedOfAbstractBase b(SecondDerived());
它不创建任何AbstractBase
临时传入的副本,并且允许存储对AbstractBase
的引用。虽然对右值引用的引用充其量看起来是不清楚的:它没有传达ComposedOfAbstractBase
拥有传入的临时值。除此之外,这个解决方案似乎不是最优的。为了说明这一点,我创建了这个类:
class ComposedOfFirstDerived {
public:
ComposedOfFirstDerived(FirstDerived first_derived) : first_derived(std::move(first_derived)) {;}
private:
FirstDerived first_derived;
};
只能占用FirstDerived
,所以我们可以应用std::move
来卸载临时寄存器的所有权。我可以这样创建一个实例:
ComposedOfFirstDerived c(FirstDerived());
有趣的是,创建这个类始终比创建ComposedOfAbstractClass
快10%。
有人知道这里发生了什么吗?为什么ComposedOfFirstDerived
的创建速度比ComposedOfAbstractBase
快得多?是否有更好的方法来使用抽象类进行组合,或者我是否陷入了次优解决方案?
ComposedOfAbstractBase
不是解决方案。你拿着一个悬空的引用。
由于AbstractBase
,顾名思义,是抽象的-您不能按值保存一个。只能通过引用或指针保存一个。因为引用不能拥有对象,所以只能使用指针。而拥有指针的现代方式是使用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
没有虚析构函数。你应该解决这个问题。
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 可组合的lambda/std::函数与std::可选
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 混合组合和继承的C++问题
- 我需要将多个函数组合为一个函数
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 通过组合不同的类型来创建唯一的id
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 模板元编程:如何将参数包组合成新的参数包
- 检查向量是否具有所有可能的字符组合
- 如何在加密++中将两个源组合成新的源
- 根中的组合
- 更改 C++ 中的组合分类变量
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 组合字符串不适用于 libCurl,C++
- 测试两个类型列表中的所有组合
- 将多个 for 循环组合成单个迭代器
- 如何从组合指数中找到仓位
- 防止组合框被关闭
- 如何解决可能的唯一组合问题