【Exceptional C++(3)】具有最大可复用性的通用C
2018-01-26 本文已影响4人
downdemo
问题
- 为下面的定长vector class实现拷贝构造操作和拷贝赋值操作以提供最大的可用性
template<typename T, size_t size>
class fixed_vector {
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin() { return v_; }
iterator end() { return v_+size; }
const_iterator begin() const { return v_; }
const_iterator end() const { return v_+size; }
private:
T v_[size];
};
解答
template<typename T, size_t size>
class fixed_vector {
public:
typedef T* iterator;
typedef const T* const_iterator;
fixed_vector() {}
template<typename 0, size_t osize>
fixed_vector(const fixed_vector<0, osize>& other)
{
copy(other.begin(),
other.begin() + min(size, osize),
begin() );
}
template<typename 0, size_t osize>
fixed_vector<T, size>&
operator=(const fixed_vector<0, osize>& other)
{
copy(other.begin(),
other.begin() + min(size, osize),
begin() );
return *this;
}
iterator begin() { return v_; }
iterator end() { return v_+size; }
const_iterator begin() const { return v_; }
const_iterator end() const { return v_+size; }
private:
T v_[size];
};
- 其实,这些并不是真正的copying函数,因为真正的copying函数只对完全相同类型的对象进行copying操作,如果是模板类,模板的参数也要完全相同
struct X {
template<typename T>
X(const T&); // 这不是拷贝构造函数,因为T不会是X
template<typename T>
operator=(const T&); // 这不是拷贝赋值运算符,因为T不会是X
- 由于模板构造函数并非拷贝构造函数,这种模板并不会隐藏默认生成的拷贝构造函数,我们只是增强了copying操作的可适应性,而不是替代掉了原有的版本
fixed_vector<char, 4> v;
fixed_vector<int, 4> w;
fixed_vector<int, 4> w2(w); // 默认的拷贝构造函数
fixed_vector<int, 4> w3(v); // 模板化的转换构造函数
w = w2; // 默认的拷贝赋值运算符
w = v; // 模板化的拷贝赋值运算符
- 增加的两个操作有两个主要用途:支持可变的类型(包括继承在内)和支持可变的大小
// 支持可变类型
fixed_vector<char, 4> v;
fixed_vector<int, 4> w(v);
w = v;
class B { ... };
class D : public B { ... };
fixed_vector<D, 4> x;
fixed_vector<B, 4> y(x);
y = x;
// 支持可变的大小
fixed_vector<char, 6> v;
fixed_vector<int, 4> w(v); // 拷贝4个对象
w = v; // 对4个对象进行赋值
class B { ... };
class D : public B { ... };
fixed_vector<D, 16> x;
fixed_vector<B, 42> y(x); // 拷贝16个对象
y = x; // 对16个对象进行赋值
- 以上函数还是有些做不到的事,下面看看标准库风格的答案
// 拷贝
template<Iter>
fixed_vector<Iter first, Iter last>
{
copy(first,
first + min(size, last - first),
begin());
}
// 进行拷贝操作时
fixed_vector<char, 6> v;
fixed_vector<int, 4> w(v.begin(), v.end()); // 拷贝4个对象
// 赋值,operator=()只接受一个参数,所以无法用范围
// 方法是提供一个具名函数
template<Iter>
fixed_vector<T, size>&
assign(Iter first, Iter last)
{
copy(first,
first + min(size, last - first),
begin());
return *this;
}
// 进行赋值操作时
w.assign(v.begin(), v.end()); // 对4个对象进行赋值
// 从技术上来说,assign()并非必需,没有它也能达到相同的可适应性
// 但是这样进行赋值操作就不太爽
w = fixed_vector<int, 4>(v.begin(), v.end());
// 所以对比最初的赋值操作,不能用可适应性来判断好坏
// 用户可能直接用
copy(v.begin(), v.end(), w.begin());
// 这种情况下就没必要写assign()了
- 虽然解答代码中给出的空的缺省构造函数和编译器合成的功能相同,但是一旦定义了一个任意的构造函数,编译器就不会合成了, 此时可能出现缺少默认构造函数的错误
- 成员函数模板很易用且被广泛用于标准库,最大的好处是极易复用