前言
该笔记是在学习裘宗燕翻译的C++程序设计特别版过程总结出的。
派生和模板
模板和派生 都是从已有类型构造新类型的机制,通常被用于去写利用各种共性的代码。这两种机制的组合是许多有用技术的基础的。 从一个非模板类派生出一个模板类,这是为一组模板提供一个公用实现的一种方法。 比如: Template<class T> class Vector<T*>: private Vector<void*> {/*…*/}; 从一个模板类派生出另一个模板类也常常很有用。 最常见的情况是基类和派生类具有同样的参数,但是这并不是一项要求。例如 Ex: Template<class T> class Basic_ops{// Public: bool operator ==(const T&)const; bool operator !=(const T&)const; //… Const T& devived()const{ return static_cast< Const T&>(*this);} }; Template<class T> class Math_container : public Basic_ops< Math_container<T>> { //… }; 保持容器与操作分离的另一种替代技术,就是通过模板参数将它们组合起来。 Template<class T,class C>class Mcontainer { C elements; //… Public: T& operator [](size_t i){return elements[i];} Friend bool operator ==<>(const Mcontainer&,const Mcontainer&); Friend bool operator! =<>(const Mcontainer&,const Mcontainer&); //… }; Template<class T>class My_array{/*…*/}; Mcontainer<double,My_array<double>> mc; 通过类模板生成的类也是完全正常的类,因此也可以有友元。 参数化、继承 虚函数提供的是运行时多态性。 模板提供的是编译时多态性 或者参数多态性。 必须将各种操作在线化,那么应该使用模板。 成员模板 一个类或者模板也可以有包含本身就是模板的成员。 Ex: Template<class Scalar>class complex{ Scalar re,im; Public: Template<class T> complex(const complex<T>& c); //不是复制构造函数 complex(const complex<Scalar>&); // 是复制构造函数 }; 如果 T2 可以对T1 初始化,那么 complex<T2> 构造 complex<T1> 。 模板构造函数绝对不会用于生成复制构造函数,复制赋值也必须定义为非模板运算符。 成员模板不能是virtual. 继承关系 将模板理解为一种有关如何生成特定类的规范,这也是一种很有用的看法。换句话说,模板实现的是一种在需要时能够基于用户描述去生成类型的机制——类型生成器 如果只考虑C++ 语言的规则,在由同一个类模板生成的两个类之间并不存在任何关系。 Ex Class Shape {/*…*/} Class Circle:public Shape{/*…*/}; std::set<Shape* > != std::set<Circle*> 模板转换 由前一节说明,由同一个模板生成的各个类之间并没有任何默认的关系。 然而 我们可以利用重载类型转换运算 来是实现 T2 参数的模板类 到 T1 参数的模板类的转换,只要存在由 T2 到 T1的转换。 Ex: Template<class T> class Ptr{// T* p; Public: Ptr(T*); Ptr(const Ptr&); Template<class C> operator Ptr<C> (); }; Template<class T> Template<class C> Ptr<T>::operator Ptr<C>(){ return Ptr<C>(p);} Void f(Ptr<Circle> pc) { Ptr<Shape> ps = pc; //ok Ptr<Circle> pc2 = ps; // error } 以上的工作必须在类型转换存在的基础上才能正确运行。 注意:一个模板的参数表与其模板成员的参数表不能组合在一起。 Ex: Template<class T,class C> //Error Ptr<T>:: operator Ptr<C>(){/*…*/}; 源代码组织