在抽象基类的不同实现中,返回不带副本的类成员与返回本地对象



假设以下设置中,我有一些抽象基类,它定义了返回的方法GetData,例如,一个std::vector和两个派生类,一个以与GetData返回的格式完全相同的格式保存数据(下面的ProperSomeClass(,另一个在内部以某种奇怪的遗留C格式保存数据,即。,必须将该格式转换为GetData中的std::vector(下面的DerivedSomeClass(。

class ISomeClass
{
virtual std::vector<int> GetData() const = 0;
};
class ProperSomeClass : public ISomeClass
{
private:
std::vector<int> _data;
public:
std::vector<int> GetData() const { return _data;  }
};
class DerivedSomeClass : public ISomeClass
{
private:
const void* _legacyFormat;
public:
std::vector<int> GetData() const
{
std::vector<int> temporary;
// some code that extracts relevant data from legacy format
return temporary;
}
};

我正在寻找一种更好的方法来定义(的返回值(GetData,这样ProperSomeClass就不必复制其_data成员。

我无法返回常量引用,因为DerivedSomeClass::GetData会返回对已删除的本地对象的引用。

当返回(智能(指针时,我必须考虑DerivedSomeClass::GetData需要分配必须由调用者释放的内存,而ProperSomeClass::GetData返回的指针所指向的内存不能由调用者释放,我不知道如何解决这个问题(除了使用shared_ptr,其中ProperSomeClass需要保存一个它永远不会使用的副本,这样它的数据就不会被删除,这对我来说似乎很难看(。

简而言之,理想情况下我"只"想要

  • ProperSomeClass::GetData在不复制数据的情况下为我提供常量引用
  • DerivedSomeClass::GetData构造矢量并返回
  • 一个通用的API在我的基类中

有办法做到这一点吗?或者,有什么替代/更好的方式来完成这一切?

这里的关键是,您希望从接口返回一些东西,根据具体的实现,这些东西要么需要由调用方销毁(返回副本/唯一所有权(,要么不需要(返回对成员的引用(。调用程序显然在编译时无法知道这一点,因此我们需要一种机制来以这种方式断言对象的破坏。你可以自己写这篇文章,以更加明确你的意图,但我认为std::shared_ptr会起作用:

#include <vector>
#include <memory>
using VectorPtr = std::shared_ptr<std::vector<int>>;
class ISomeClass
{
virtual VectorPtr GetData() const = 0;
};
class ProperSomeClass : public ISomeClass
{
private:
VectorPtr _data;
public:
VectorPtr GetData() const { return _data;  }
};
class DerivedSomeClass : public ISomeClass
{
private:
const void* _legacyFormat;
public:
VectorPtr GetData() const
{
VectorPtr temporary;
// some code that extracts relevant data from legacy format
return temporary;
}
};

您可以将std::vector添加到您在ctor中初始化的DerivedSomeClass中,并在GetData中作为const-ref返回,即:

class DerivedSomeClass : public ISomeClass
{
public:
DerivedSomeClass(void* legacyFormat):
_legacyFormat(legacyFormat),
_data(makeVectorFromLegacy(_legacyFormat))
{}
private:
const void* _legacyFormat;
const std::vector<int> _data;
public:
const std::vector<int>& GetData() const
{
return _data;
}  
};

使用一个助手函数从const void*指针创建该向量,就像在DerivedSomeClass::GetData()中提取数据一样,只需执行一次。

这与ProperSomeClass略有重复,这对您来说可能很好,也可能不好,尽管它的优点是不会在每个派生类上强制使用std::vector成员变量,从而考虑到未来可能不需要或不想要该成员std::vector的潜在实现。

ISomeClass的一个定义属性是它使std::vector<int>可用。由于ProperSomeClassDerivedSomeClass都是从ISomeClass导出的,所以它们都必须以相同的方式使该向量可用。例如,如果您希望通过const引用实现这种方式,这在我看来非常合理,那么您需要向量是这两个类的成员。

考虑在DerivedSomeClass中有一个成员std::vector<int>。如果你想避免两次存储相同的数据(在向量和"遗留格式"指针中(,你可能可以在构造函数中而不是DerivedSomeClass::GetData中"提取相关数据",并去掉_legacyFormat成员。

如果DerivedSomeClass绝对需要保留_legacyFormat,我认为这个类和ProperSomeClass应该分开。

最新更新