类模板 --- 下 --- 特化、模板参数、智能指针
2017-02-27 20:19
176 查看
类模板的局部特化
类模板可以定义多个类型参数。如下图所示:
类模板可以被局部特化
可以指定类模板的特定实现,并要求某些类型参数仍然必须得模板的用户指定。
编译器会优先选择经过特化的类模板。
为什么需要特化,而不重新定义新类?
特化和重新定义新类看上去没有本质区别,但是如果定义新类,那么将变成一个类模板和一个新类,使用的时候需要考虑究竟是用类模板还是用新类。
而特化可以统一的方式使用类模板和特化类,编译器自动优先选择特化类。
非类型模板参数
函数模板和类模板的模板参数可以是普通数值。非类型模板参数与特化,代码实例:
//采用类模板和特化类实现从1加到100 #include <cstdlib> #include <iostream> using namespace std; //本代码求1-n相加的和,不分配空间,不调用函数,效率高 template<int N>//类模板 class Sum { public: static const int VALUE = Sum<N - 1>::VALUE + N; // static表明是静态成员变量 // const表明这是常量会被放到符号表中,不会分配空间 // 在编译的过程中就已完成了递归 // 编译器完成了计算,在程序执行的时候不再花费时间 }; template<> //特化类,没有特化类,递归就无法结束 class Sum<1> { public: static const int VALUE = 1; }; int main(int argc, char *argv[]) { cout<<Sum<10>::VALUE<<endl; cout<<Sum<100>::VALUE<<endl; cout<<sizeof(Sum<100>)<<endl;//大小为 1 字节 cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS; }
非类型模板参数的限制:
变量不能作为模板参数。
浮点数和类对象不能作为模板参数。
全局指针不能作为模板参数。
只有整形作为模板参数比较安全。
编译器的推导过程是在编译阶段完成的。因此,编译器的推导必须依赖于特化类,否则推导过程无法结束。当没有定义特化类时,编译就会报错。
工程问题
在实际工程中内存操作是bug的重要来源C++将堆内存交由程序员自由使用,因此有如下的几种bug:1、未及时释放,将产生内存泄漏
2、重复释放同一段内存,行为未知
3、使用越界,操作了不属于自己的内存
内存越界的问题常发生于数组的使用中。
解决方案:数组类
工程中,在非特殊情况下,要求开发者使用预先编写的数组类对象代替C语言中的原生数组。
内存泄漏和内存多次释放常发生于指针的使用过程中。
解决方案:智能指针
工程中,要求开发者使用预先编写的智能指针类对象代替C语言中的原生指针。
智能指针 smart point
工程中的智能指针是一个类模板:通过构造函数接管申请的堆内存。
通过析构函数确保堆内存被及时释放。
通过重载指针运算符 * 和 -> 模拟指针的行为。
通过重载比较运算符 == 和 != 模拟指针的比较。
智能指针的创建与使用,代码举例:
//智能指针 类定义 头文件 SmartPoint.h #ifndef _SMARTPOINTER_H_ #define _SMARTPOINTER_H_ template<typename T> //类模板 class SmartPointer { protected: T* m_pointer; public: SmartPointer(); SmartPointer(const T* pointer); ~SmartPointer(); T* operator->(); T& operator*(); bool operator==(const SmartPointer<T>& operater); bool operator!=(const SmartPointer<T>& operater); }; #endif
//智能指针 类成员函数定义 头文件 SmartPoint.hpp #ifndef _SMARTPOINTER_DEF_H_ #define _SMARTPOINTER_DEF_H_ #include "SmartPointer.h" template<typename T> SmartPointer<T>::SmartPointer()//构造函数 { m_pointer = NULL; } template<typename T> SmartPointer<T>::SmartPointer(const T* pointer)//构造函数 { m_pointer = const_cast<T*>(pointer); } template<typename T> SmartPointer<T>::~SmartPointer()//析构函数 { delete m_pointer; } template<typename T> T* SmartPointer<T>::operator->()//操作符重载 { return m_pointer; } template<typename T> T& SmartPointer<T>::operator*()//操作符重载 { return *m_pointer; } template<typename T> bool SmartPointer<T>::operator==(const SmartPointer<T>& operater) { return m_pointer == operater.m_pointer; } template<typename T> bool SmartPointer<T>::operator!=(const SmartPointer<T>& operater) { return m_pointer != operater.m_pointer; } #endif
//智能指针 main文件 main.cpp #include <cstdlib> #include <iostream> #include "SmartPointer.hpp" using namespace std; class Test { public: int i; void print() { cout<<i<<endl; } }; int main(int argc, char *argv[]) { SmartPointer<int> pi (new int(5));//构造函数 SmartPointer<Test> pt (new Test()); SmartPointer<int> pj = pi; cout<<*pi<<endl; *pi = 10;//使用重载操作符 cout<<*pi<<endl; pt->i = 20;//使用重载操作符 pt->print(); if (pi != pj)//使用重载操作符 { cout<<"!="<<endl; } else { cout<<"=="<<endl; } cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS; }
小结
类模板中可以有一个或多个未指定的泛指类型。可以在需要的特化类模板。
特化可以统一的方式使用类模板和新定义的类。
特化类总是被编译器优先选择使用。
模板的参数可以是普通数值。
数组类和智能指针可以最大限度的避免内存相关的bug。
相关文章推荐
- 类模板的特化,局部化以及缺省模板的实参
- 07 C++模板特化、模板偏特化和模板模板参数基本用法
- day_13_类模板(参数、数组、特化)
- 类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器
- c++ 模板学习笔记:理解类模板的特化与偏特化(权哥)
- 类模板中非类型参数的模板实参
- 类模板中非类型参数的模板实参
- 类模板作为函数参数以及作为类模板参数的一个简单示例
- 成员模板、模板的偏特化和特化、模板模板参数
- [置顶] C++泛型编程1——函数模板实例化,模板参数,重载及特化
- 类模板——类模板的特化问题
- 类模板的特化和函数模板的重载与类模板的继承
- C++ 类模板中非类型参数的模板参数
- 模板完全特化,函数重载的重载,类模板的继承
- C++模板实现模块间参数传递及回调之二
- C++ 函数模板和类模板(转)
- 如何将一个模板类A作为模板类B的模板参数
- 用Quartus II 建立一个工程模板,以后新建工程时无需再配置参数
- 模板特化和偏特化
- 参数模板加载报错