假设以下设置中,我有一些抽象基类,它定义了返回的方法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>
可用。由于ProperSomeClass
和DerivedSomeClass
都是从ISomeClass
导出的,所以它们都必须以相同的方式使该向量可用。例如,如果您希望通过const引用实现这种方式,这在我看来非常合理,那么您需要向量是这两个类的成员。
考虑在DerivedSomeClass
中有一个成员std::vector<int>
。如果你想避免两次存储相同的数据(在向量和"遗留格式"指针中(,你可能可以在构造函数中而不是DerivedSomeClass::GetData
中"提取相关数据",并去掉_legacyFormat
成员。
如果DerivedSomeClass
绝对需要保留_legacyFormat
,我认为这个类和ProperSomeClass
应该分开。