C++泛型编程

泛型编程

什么是泛型编程?简单说泛型编程就是使用一种通用类型来进行程序设计的方法,这个方法可以大规模的减少程序代码的编写量

函数模板,类模板都属于是泛型编程,他们都使用了一种数据类型T

T是一个数据类型占位符,也可以把T当作一种数据类型,即泛型,使用这个占位符的编程方式即是泛型编程

自动推导类型

自动推动类型使得泛型编程使用更方便,在介绍模板之前先介绍自动推导类型

auto关键字

auto关键字作为类型指示符,可以在编译时自动推导数据类型,在使用时用auto代替原来的数据类型(一般是复杂的)

语法:auto 变量名=初始值;

auto声明的变量必须在定义时初始化

初始化的右值可以是具体的数值,也可以是表达式和函数的返回值等

auto不能作为函数的形参类型,即参数列表不能用auto

auto不能直接声明数组

auto不能定义类的非静态成员变量

auto一般用于:

1.代替复杂的变量声明

2.在模板中,用于声明模板参数有关的变量// 例如在模板类中的一个模板函数里面的一个局部变量,还未实例化前无法确定其数据类型,这时用auto,延续其泛用性

3.用于与模板参数有关的函数返回值//同上

4.用于lambda表达式

decltype关键字

decltype关键字用于查询表达式的数据类型

语法:decltype(expression) var;

expression可以是表达式,函数,变量... var与expression类型相同,可以是一个变量也可以是函数指针取决于expression

1)如果expression是一个没有用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const等限定符。

2)如果expression是一个函数调用,则var的类型与函数的返回值类型相同//函数调用func()和函数名func不一样,表达式若是函数名则类型为函数类型

3)如果expression是一个左值(能取)(要排除第一种情况)例如a++、或括号括起来的标识符,那么var的类型是expression的引用。

4)如果上面的条件都不满足,则var的类型与expression的类型相同。

总的来说decltype获取表达式数据类型或者是表达式数据类型的引用

引用必须初始化 

函数后置返回类型

这个是C++14前遗留的东西,面对复杂的函数返回类型时可以用auto代替,然后在后面加上返回类型,即返回类型后置

auto func(int x,double y) -> int
{
    // 函数体。
}

在C++14之后后面不用加返回类型

函数模板 

什么是函数模板?函数模板是通用函数的描述,用泛型来描述函数,编译时根据实参数据类型和函数模板生成函数定义

生成函数定义的过程被称为实例化

函数模板举例:
template 
void Swap(T &a, T &b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

1)  不能为虚函数和析构函数创建函数模板

2)使用函数模板时,必须明确数据类型,确保实参与函数模板能匹配上//Swap(a,b)

3)使用函数模板时,推导的数据类型必须适应函数模板中的代码。

4)使用函数模板时,如果是自动类型推导,不会发生隐式类型转换,如果显式指定了函数模板的数据类型,可以发生隐式类型转换。//Swap(7.2,8)  double->int

5)函数模板支持多个通用数据类型的参数。

6)函数模板支持重载,可以有非通用数据类型的参数。

函数模板具体化 

什么是具体化?具体化又称特例化,特化,是把函数模板中的泛型T具体成某一种数据类型;

具体化又分为部分具体化和完全具体化

部分具体化举例:
template 
void Swap(T1 &a, int &b)
{
	T1 tmp = a;
	a = b;
	b = tmp;
}
完全具体化举例:
template 
void Swap(char &a, int &b)
{
	char tmp = a;
	a = b;
	b = tmp;
}

具体化是为了完成一些特殊的需求,而不是把他当成泛型来对待 

 1)具体化优先于常规模板,普通函数优先于具体化和常规模板。

2)如果希望使用函数模板,可以用空模板参数<>强制使用函数模板。

3)如果函数模板能产生更好的匹配,将使用函数模板 

 具体化程度高的优先于具体化程度低的

模板类 

类模板是通用类的描述,使用泛型来描述类的定义

template 
class 类模板名
{
	类的定义;
};

 1)在创建对象的时候,必须指明具体的数据类型。//与函数模板不一样

2)使用类模板时,数据类型必须适应类模板中的代码。

3)类模板可以为通用数据类型指定缺省的数据类型

4)可以用new创建模板类对象。

5)在程序中,模板类的成员函数使用了才会创建。//无论是函数模板还是类模板在实例化前都是不存在的,因此不使用模板即使模板内部有语法错误也不会报错 

模板类具体化

模板类的具体化和函数模板具体化一样,都分为部分具体化和完全具体化

部分具体化类模板:
template
class AA {      
类定义
}
完全具体化类模板:
template
class AA {      
类定义
}

模板类的嵌套

例子:假设自定义了一个类A,在创建A类对象时在模板参数列表中使用A//vector> v;

模板类与继承 

1)模板类继承普通类(常见)class BB:public AA

2)普通类继承模板类的实例化版本。class AA:public BB  ,模板类的实例化版本相当于普通类

3)普通类继承模板类。(常见)

template

class AA:public BB

4)模板类继承模板类。

template

class CC :public BB

5模板类继承模板参数给出的类(不能是模板类),也就是嵌套的另一种情况:模板类继承模板类的具体化版本或者继承普通类

 EE> ed1;


普通类继承模板类必须先将自身变成模板

模板类作为函数的参数和返回值

模板类可以用于函数的参数和返回值,有三种形式:

1)普通函数,参数和返回值是模板类的实例化版本。AA func(AA& aa)

2)函数模板,参数和返回值是某种的模板类。

template

AA func(AA& aa)

3)函数模板,参数和返回值是任意类型(支持普通类和模板类和其它类型)

template

T func(T &aa)

模板类和友元

模板类的友元函数有三类:

 1)非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内定义 friend void show(const AA& a)

2)约束模板友元:友元函数是模板,模板类实例化时,每个实例化的类对应一个友元函数。friend void show<>(AA& a)

3)非约束模板友元:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。 

分文件编写

函数模板,类模板都要进行分文件编写

声明放在头文件中,定义放在源文件中

模板在没实例化之前可以当作声明看待,一旦具体化就要像普通函数普通类一样对待

ps:具体化的类模板声明定义都放在头文件中

你可能感兴趣的:(C++,c++,开发语言)