美文网首页Exceptional C++
【Exceptional C++(3)】具有最大可复用性的通用C

【Exceptional C++(3)】具有最大可复用性的通用C

作者: downdemo | 来源:发表于2018-01-26 14:13 被阅读4次

问题

  • 为下面的定长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()了
  • 虽然解答代码中给出的空的缺省构造函数和编译器合成的功能相同,但是一旦定义了一个任意的构造函数,编译器就不会合成了, 此时可能出现缺少默认构造函数的错误
  • 成员函数模板很易用且被广泛用于标准库,最大的好处是极易复用

相关文章

网友评论

    本文标题:【Exceptional C++(3)】具有最大可复用性的通用C

    本文链接:https://www.haomeiwen.com/subject/rlniaxtx.html