运算符重载函数的限制:
- 五个不能实现重载的符号:".", ".*", "::", "?", "sizeof";
- 重载运算符可以定义为类成员函数(这时候可以向当前对象发送消息的动作执行操作),也可定义为全局函数(一般为对应类的友元函数,此类函数需要显式指定所有参数,并且如果有转换构造函数,则可以使用于所有参数类型的运算);
- 一般的重载运算符函数可以被派生类继承使用,但是赋值运算符重载函数不能被继承;因此每一个派生类都最好定义自己的赋值运算符重载函数;
- 重载运算符函数需要与运算符本身的属性保持一致:优先级,结核性,参数个数等;
转换构造函数一般使用于隐式调用,用于将一般类型转换为当前类的类型,而转换运算符函数一般适用于显式转换,用于将当前类型转换为其他类型(注意这个函数没有返回值,但是需要使用return返回对应的类型数据,并且不能有任何参数)
输入输出运算符的重载一般形式为:(实现为全局函数,并且支持链式操作)
1 public : friend istream& operator >> (istream& in, String &s);
2 public : friend ostream& operator << (ostream& out, String &s);
为了让程序适用于多种不同类型:
- 可以将关键变量的类型使用typedef定义为一个内部变量,但是不支持多种类型同时使用同一算法容器的情况,也就是每改变一次参数类型,程序都需要重新编译:
typedef char Type;
class Stack {Type *items; ……};
- 还可以使用#define宏定义将整个程序代码创建成宏定义,由于宏定义中的参数不会进行类型检查,所以可以将关键字类型定义为参数的内部变量。由于宏定义语句中基本不能进行调试,所以这不能大规模使用;
- 模板类(template class),将元素的类型作为类的可选参数,可以用同一算法容器支持所有具有所需操作的类型的变量的处理
定义模板类:(类方法的实现体之前需要声明模板类型标记)
1 template <class Type>
2 class Stack {
3 Type *items;
4 ……
5 ~Stack();
6 void push(const Type&);
7 };
8 template <class Type>
9 Stack<Type>::~Sack();
10 template <class Type>
11 void Stack<Type>::push(const Type&){……}实例化具体类:
Stack<char> charString(20);
charString.push(‘i‘);
模板类定义和实例化的限制:
- 模版类中定义的类别名需要在对象实例化过程中使用实际的类型替换,但要求这种类型支持类定义中的所有操作,否则会在编译时期报错;因此在编译阶段到达模板类实例化具体类的时候,就会针对实际传入的类类型进行语法查错,如果传入类型支持所有的操作则正确生成对应的代码;
- 形如:template <class T1, class T2, int
size>中T1和T2是定义的类型,实例化中需要使用具体的类型名初始化,size则是一个数值,实例化的时候需要使用具体的数值进行初始化,并
且这个初始化值不能是运行期变量,需要const变量或者是数值常量(编译期间就能确定的值) - 将某个模板类申明为友元类
template <class T>
class Stack {};
class Node {template <class T> friend class Stack};
或者
template <class Type>
class Node {friend class Stack<Type>;};
- 如果一个模板类声明了静态数据成员,那么每一个模板的实例都将独立拥有一份静态数据成员的内存数据;也就是说模板实例化将重新创建一份独立的类代码,相同
模板的不同实例之间不会共享任何内存;对于模板类的静态成员而言,其也会进行缺省初始化,但其不同于一般的静态数据成员会在程序开始之前进行,而是在具体
实例化一个模板对象(也就是指定类参数)的时候进行:template <class T>
class Stack
{
static Stack
*top;
};模板静态成员的初始化:
template <class T>
Stack<T>* Stack<T>::top=NULL;
模版机制是在编译时期而不是运行时期进行数据类型检查,所以更加安全,并且可用于基本类型,不像多态技术只能用于类的成员函数,同时其绑定时期也在编译阶段,所以运行效率更高:模版机制是在编译时期而不是运行时期进行数据类型检查,所以更加安全,并且可用于基本类型,不像多态技术只能用于类的成员函数,同时其绑定时期也在编译阶段,所以运行效率更高:
- 模版的优势:
可用来创建动态增长和减小的数据结构;
它是类型无关的,因此具有很高的可复用性;
它在编译时而不是运行时检查数据类型是否与操作匹配,保证了类型安全;
它是平台无关的,可移植性;
可用于基本数据类型;
- 模版用途:同样的逻辑表示,只是因为不同的参数或者返回值类型而不同公用同一套逻辑,这时候需要将类型转变成可替换的;
- 宏定义虽然也可以实现为多种类型提供一套逻辑实现,但是它避开了类型检查,使得程序调试难以实现,并且由于是文本替换,所以容易出现副作用;
- 模版是实现代码复用的一种工具,可以实现类型参数化,将类型定义为参数,在编译时候进行类型检查(查看用户传入类型是否支持该类型所有的操作);
- 函数模板的实例化是由编译程序在处理函数调用时自动完成的(静态绑定),而类模板的实例化必须由程序员在程序中显式地指定;
- 模版分成两类,函数模版:
声明格式为:
Template <typename [类型参数标示]> [返回类型] [函数名](参数列表)其中的typename也可以替换为class,并且template和函数头之间不能再有其他语句;
支持多个类型的参数化,但是每个类型参数之前需要添加typename或者class;
允许通过不同的参数类型而进行重载,但是仅仅支持全特化;
- 模版分成两类,类模版:
声明格式:
Template <typename [类型参数标示]> Class [类名]{类定义}类成员函数实现时,所有方法前都需要添加template <typename [类型参数标示]>,可以进行全特化和偏特化;
特化机制是建立在一般模板类定义(模板函数同样适用)的基础上的,对其中的某一个或者某几个类型参数进行特化定义的机制;编译器进行选择时首先从特化程度
最大的模板定义中选择合适的定义,最后才考虑一般模板定义。STL模版特化(Template Specialization)和偏特化(Template
Partial Specialization):
- 模板特化:指定一个或者多个模板形参的实际类型或者实际值,如下所示第一个函数Compare是一般的模板实现,第二个Compare函数就是第一个模板函数的特化,所以编译中如果形参类型是const
char*, const char* 则调用第二个特化函数:1 template <typename T>
2 int Compare(const T &x, const T &y)
3 {
4 if(x < y)
5 return -1;
6 else if(x > y)
7 return 1;
8 else
9 return 0;
10 }
11 template <> //template关键字后面接空括号
12 int Compare(const char * const &x, const char * const &y) //形参为指向常量的常指针的引用
13 {
14 return strcmp(x, y);
15 }参考链接:
http://blog.csdn.net/wuzhekai1985/article/details/6654667 - 模板的偏特化:需要根据模板的某些但不是全部参数进行特化:
1 //1
2 template <class T>
3 class Array {T *data;};
4 //2
5 template <>
6 class Array <char *> {char* data;};//1
7 template <class T>
8 class Array {T *data;};
9 //2
10 template <>
11 class Array <char *> {char* data;};这样当使用Array<int> a;的时候编译器自动匹配一般的模板,当使用Array<char*>
a的时候则编译器匹配第二个特殊化的模板,这样就可以针对具体的类型实现不同的类实现;函数的特化与类的特化类似;当模板参数有多个的时候,编译器支持部分参数的特化:
1 //1
2 template <class Key, class Data>
3 class Item {Key key; Data data;};
4 //2
5 template <class Data>
6 class Item <char *> {char *key, Data data};
7 //3
8 template <>
9 class Item <char *, char *> {char *key, char *data};
10 //4
11 template <class key>
12 class Item <key, char *> {Key key, char *data};特化参数需要遵循从左向右的顺序,可以偏特化,也可以全特化;实际调用中会根据匹配程度最大的模板生成对应的代码;当然也可以仅特化第二个参数,但是需要在类定义中添加第一个类型参数的占位符;
为什么需要Type-Traits:
- 对于不同类型执行相同的操作,希望有一个公用的接口,然后根据具体的类型实现不同的调用;
- 基于虚函数实现的多态机制只能针对类定义对象,对于语言内置类型,指针类型并不适用;
- 多态机制是动态绑定,在某种程度上比编译时期绑定更加耗时,type-traits可以在编译时期进行绑定;
C/C++知识点总结(5),布布扣,bubuko.com