C++ 使用只在构造函数中不同的类有哪些优点和缺点?
我有一个类C++ 使用只在构造函数中不同的类有哪些优点和缺点?,c++,oop,C++,Oop,我有一个类SpecialArray,可以用与标准二维数组相同的方式访问它;i、 例如,作为A[i][j]。通常需要从该对象中提取int的一维数组。提取的细节(取决于其他传递的参数)无关紧要;我对设计操作界面感兴趣 以下完成此任务的方法的优点和缺点是什么 选项1 我们定义了一个函数: std::vector<int> extract(const SpecialArray &A, ...) 选项2 我们创建了一个从std::vector继承的类,并构造它自己: class Sp
SpecialArray
,可以用与标准二维数组相同的方式访问它;i、 例如,作为A[i][j]
。通常需要从该对象中提取int
的一维数组。提取的细节(取决于其他传递的参数)无关紧要;我对设计操作界面感兴趣
以下完成此任务的方法的优点和缺点是什么
选项1
我们定义了一个函数:
std::vector<int> extract(const SpecialArray &A, ...)
选项2
我们创建了一个从std::vector继承的类,并构造它自己:
class SpecialArrayExtract : public std::vector<int> {
public:
SpecialArrayExtract(const SpecialArray &A, ...);
};
选项3
我们完全按照选项2进行操作,但不继承自std::vector
,而是拥有一个private
成员std::vector
,根据需要公开接口:
class SpecialArrayExtract {
private:
std::vector<int> m_data;
public:
SpecialArrayExtract(const SpecialArray &A, ...);
[Wrapper functions for std::vector<int> here.]
};
class SpecialArrayExtract{
私人:
std::向量m_数据;
公众:
特殊射线提取物(const Speciallarray&A,…);
[此处是std::vector的包装函数。]
};
评论
该应用程序是高性能的,但是在选项1中使用RVO时,我假设这些应用程序的性能应该是相等的
将此与标题联系起来,我想指出的一点是,选项2和3都定义了一些类,这些类本质上只是
std::vector
,具有不同的名称和特殊的构造函数。什么时候——如果有的话!——这是一个合理的想法吗?哪种方法更好?选项4
为类SpecialArray实现公共成员函数:
std::vector<int> extract(...);
std::向量提取(…);
我认为选项一最有意义,因为它:
- 有一个非常简单的接口
- 不创建其他类
- 可以通过模板扩展其他“提取”操作
std::vector
继承,你是说specialrayextract
是-astd::vector
,并提供一个单独的操作(构造函数)来创建它。如果你想一想,这只是一个复杂的方式来做完全一样,你的第一个选择
选项三似乎是一个过早的优化(您选择的是包含而不是继承,好像您会先发制人地期望底层数据容器发生变化),这比选项二更复杂
至于选项4(在回答中建议),我认为类接口应该保留尽可能少的实例方法,而不是提供非成员函数(请参阅了解基本原理)
如果将来需要更改(例如,您决定另一个容器或数据类型更好地满足您的需要),您可以通过模板修改函数。这将为您提供拥有单独类的所有优势,但不会增加开销。相同的操作(具有完全相同的名称)可以应用于任何可能的容器类型组合(即,std::vector
,或std::array
,或其他)和数组类型(specialray
,或SparseSpecialArray
,或其他):
模板
ContainerType提取(常量数组类型和数组,…)
最后,您可以创建一个单独的
算法
命名空间,其中包含作用于数组类型
数据的所有函数(例如,SpecialArray
)。这将使记录和维护代码变得非常简单:数据类型的所有通用操作都存在于算法中::
,对于此类操作,命名空间是一个更自然的聚合器,而不是一个具有许多静态方法的类。我个人只需实现一个ToVector(…)方法在SpecialArray类中。如果您没有访问源代码的权限(我相信您有),您可以将该方法作为扩展添加到该类中
据我所知,你的问题是你的内存中有一个特殊的数组,你想把它转换成std::vector。如果这两个类在内存中都是隔离的(即没有缓存来提高转换性能),那么您只需要一个方法来获取SpecialArray并将其转换为std::vector。不管它是构造函数还是常规方法,只要SpecialArray是通过引用传递的
template < typename OutIt >
void extract(SpecialArray const&, OutIt dest_begin);
例如:
SpecialArray my_special;
constexpr std::size_t len = 100;
int dest_ra[len];
std::array<int, len> dest_a;
std::vector<int> dest_v;
std::list<int> dest_l;
if( len >= my_special.extract_length() )
{
extract( my_special, std::begin(dest_ra) );
extract( my_special, std::begin(dest_a) );
}
// using `push_back`:
dest_v.reserve( my_special.extract_length() ); // not necessary
extract( my_special, std::back_inserter(dest_v) );
extract( my_special, std::back_inserter(dest_l) );
// if random access is required, also a bit faster(*):
dest_v.resize( my_special.extract_length() );
extract( my_special, std::begin(dest_v) );
// not possible for the list
specialray my_special;
constexpr std::size\u t len=100;
内部目的地[列];
std::数组dest_a;
std::向量dest_v;
标准:列出目的地;
如果(len>=my_special.extract_length())
{
摘录(my_special,std::begin(dest_ra));
摘录(my_special,std::begin(dest_a));
}
//使用“推回”:
dest_v.reserve(my_special.extract_length());//没必要
摘录(my_special,std::back_inserter(dest_v));
摘录(my_special,std::back_inserter(dest_l));
//如果需要随机访问,也要快一点(*):
dest_v.resize(my_special.extract_length());
摘录(my_special,std::begin(dest_v));
//对于列表来说不可能
(*)back\u insert\u迭代器必须进行范围检查以放大向量。如果使用普通迭代器,则不进行范围检查
我喜欢Arrieta的论证,并同意对选项的判断。那么您有一个包含多个数组的数据结构,并且需要提供对整个数组的访问?提取方法从内部存储的数组复制到目标数组(无论是RVO还是move语义);真的有必要复制它吗?选项2非常糟糕,您不应该公开继承std::vector,因为它没有虚拟析构函数…@DyP提取的数组是原始多维数组中的元素序列,这些元素是
template<typename ContainerType, typename ArrayType>
ContainerType extract(const ArrayType& array, ...)
template < typename OutIt >
void extract(SpecialArray const&, OutIt dest_begin);
std::size_t extract_size() const;
SpecialArray my_special;
constexpr std::size_t len = 100;
int dest_ra[len];
std::array<int, len> dest_a;
std::vector<int> dest_v;
std::list<int> dest_l;
if( len >= my_special.extract_length() )
{
extract( my_special, std::begin(dest_ra) );
extract( my_special, std::begin(dest_a) );
}
// using `push_back`:
dest_v.reserve( my_special.extract_length() ); // not necessary
extract( my_special, std::back_inserter(dest_v) );
extract( my_special, std::back_inserter(dest_l) );
// if random access is required, also a bit faster(*):
dest_v.resize( my_special.extract_length() );
extract( my_special, std::begin(dest_v) );
// not possible for the list