python+网站开发+prf,网页设计专业公司,如何下载js做的网站,微网站自助建站后台目录
一. 前言
二. 泛型编程
三. 函数模版
3.1 函数模版的概念
3.2 函数模版的格式
3.3 函数模版的原理
3.4 函数模板的实例化
3.5 模板参数的匹配原则
四. 类模版
4.1 类模版的定义
4.2 类模版的实例化 一. 前言 本期我们要介绍的是C的又一大重要功能----模版。通… 目录
一. 前言
二. 泛型编程
三. 函数模版
3.1 函数模版的概念
3.2 函数模版的格式
3.3 函数模版的原理
3.4 函数模板的实例化
3.5 模板参数的匹配原则
四. 类模版
4.1 类模版的定义
4.2 类模版的实例化 一. 前言 本期我们要介绍的是C的又一大重要功能----模版。通过模版我们可以很轻松的进行泛型编程大大简化我们编程时的代码。 本文的目标是让读者对模版有一定程度上的了解以便后续STL的学习对于模版更深层次的内容我们放到以后再进行拓展。 话不多说开启我们今日的学习叭
二. 泛型编程 假如现在有个需求要求我们实现一个swap函数用于数据的交换数据类型可能是整形、浮点型、字符型等等通过我们之前学习的知识你会如何进行实现呢 聪明的你可能会这样实现
//利用函数重载实现三种不同类型的swap函数
void Swap(int x, int y) //引用传参
{int tmp x;x y;y tmp;
}void Swap(double x, double y)
{double tmp x;x y;y tmp;
}void Swap(char x, char y)
{double tmp x;x y;y tmp;
} 是的上面的代码确实实现了我们的需求但还是存在一些不足体现在如下两个方面
几个重载函数仅仅是类型不同代码逻辑都是一样的代码的复用率比较低。每当有新类型出现时用户就需要再自行添加一个函数代码的可维护性比较低一个出错可能所有的重载均出错(想必你写的时候也是CV的叭) 依照以上两点不足那我们能不能只给编译器提供一个模板到时候让编译器根据我们指定的类型自动生成所需要的函数呢 答案是有的。C为我们提供了模版的概念支持我们进行泛型编程。模版就好比一个模具我们可以从倒入任何种类(类型)的东西到模具中最终都会形成我们想要的对应图案(即生成相应的代码) 泛型编程编写与类型无关的通用代码是代码复用的一种手段。模版是泛型编程的基础。模板分为函数模版和类模版 三. 函数模版
3.1 函数模版的概念 一个函数模版代表了一个函数的整个家族。该函数模板与类型无关在使用时被会被实例化根据实参类型实例化出特定类型的函数版本。
3.2 函数模版的格式 函数模版的定义格式如下所示 templatetypename T1, typename T2,......,typename Tn 返回值类型 函数名(参数列表){} 例如我们将上面的swap函数定义为函数模版如下
templatetypename T //T是类型名
void swap(T x, T y)
{T tmp x;x y;y tmp;
} 其中typename是定义模版参数的关键字也可以使用class关键字替代。 3.3 函数模版的原理 我们可以把函数模板看做一个蓝图它本身并不是一个函数而是编译器根据调用函数时传入实参产生特定类型函数的一个模具。 例如当我们给swap函数传入double类型的参数编译器就会自动根据模板生成一份参数为double类型的swap函数而如果我们传入的是int类型的参数编译器就会生成一份参数为int类型的swap函数。 由此可见模板就是将本来应该我们做的重复的事情交给了编译器去做将手动敲出来的代码变为编译器自动生成。 在编译器编译阶段时对于模板函数的使用编译器需要根据传入的实参类型来推演T并生成对应类型的函数以供调用。比如当double类型数据使用函数模板时编译器通过对实参类型的推演将T确定为double类型然后产生一份专门处理double类型的代码对于其余类型也是如此。 3.4 函数模板的实例化 当不同类型的参数使用函数模板时编译器根据模版为这个类型生成一份函数代码这个过程称为函数模板的实例化。模板参数实例化分为隐式实例化和显式实例化。 隐式实例化 即编译器根据实参的类型自动推导模版参数的类型
templateclass T
T Add(const T left, const T right)
{return left right;
}int main()
{double d1 2.0;double d2 5.0;Add(d1, d2); //d1和d2是double类型的编译时编译器推导T为double类型实例化double类型的Add函数int i1 0;Add(i1, d2); //此处编译会报错因为Add只有一个模板参数T而实参有两种类型编译器推导时不知道将T推导为int还是doublereturn 0;
} 可以看到编译器进行隐式实例化也不是胡乱实例化的必须要有唯一的结果编译器才会进行实例化编译器一般不会进行类型转换操作因为一旦转化出问题编译器就需要背黑锅。 要解决上面Add函数的问题我们有两个解决方法 1、用户自行进行强制类型转换
Add(i1, (int)d2); //将两个实参都变为int类型Add((double)i1, d2); //将两个实参都变为double类型 2、使用下面的显式实例化 显式实例化 调用函数时我们可以在函数名后使用来指定模板参数的实际类型如下
int main()
{int a 10;double b 20.0;double c 30.0;// 显式实例化Addint(a, b); //显式指定T实例化为intAdddouble(b, c); //显式指定T实例化为doublereturn 0;
} 当实例化的函数形参和实参的类型不匹配时编译器就会尝试进行隐式类型转换如果无法转换成功编译器将会报错
templatetypename T
void Swap(T x, T y)
{T tmp x;x y;y tmp;
}
int main()
{int i 10;double d 10.0;Swapint(i, d); //尽管我们显式进行实例化了但这里编译器仍然会报错原因是形参和实参无法进行隐式类型转换return 0;
}3.5 模板参数的匹配原则 1、 一个非模板函数可以和一个同名的函数模板同时存在并且该函数模板还可以被实例化为这个非模板函数。换句话说我们既可以使用非模板函数也可以使用编译器特化的模板函数。
//Swap函数模板
templateclass T
void Swap(T x, T y)
{T tmp x;x y;y tmp;
}//处理int类型的Swap函数
void Swap(int x, int y)
{int tmp x;x y;y tmp;
}int main()
{int a 10, b 20;Swap(a, b); //使用下面专门处理int的Swap函数Swapint(a, b); //使用上面编译器特化后的Swap函数return 0;
} 2、对于非模板函数和同名函数模板调用时会调用最匹配的那个函数。在其他条件相同的情况下编译器会优先调用非模板函数。如果模板可以产生一个更匹配的函数则将选择模板。
//Add函数模板
templateclass T1,class T2
T1 Add(T1 x, T2 y)
{return x y;
}//处理int类型的Add函数
int Add(int x, int y)
{return x y;
}int main()
{Add(10, 20); //虽然可以通过模板生成int,int的模板函数但编译器并不会去生成而是去调用已经存在的非模板函数Add(10, 20.0); //通过函数模板生成的函数会更加匹配故调用函数模版生成的Add函数return 0;
} 3、模板函数不允许自动类型转换但普通函数可以进行自动类型转换
//Add函数模板
templateclass T
T Add(T x, T y)
{return x y;
}int Swap(int x, int y)
{int tmp x;x y;y tmp;
}int main()
{int a 20;double d 10.0;Add(d, a); //这里会报错Add是模板函数不支持自动类型转换Swap(d, a); //这里编译通过d会发生隐式类型转换为int类型return 0;
} 四. 类模版
4.1 类模版的定义 在C中除了普通函数支持模版类也支持模版我们把这样的类称为类模版。下面给出一个类模版的定义格式
templateclass T1, class T2, ..., class Tn //模板参数
class 类模板名
{// 类内成员定义
}; 下面我们用vector类来演示一下类模板的定义方法以及注意事项(只是演示噢并不是真正的vector模拟实现)
//vector类
templateclass T
class Vector
{
public://构造时使用new动态申请空间Vector(int capacity 10):_p(new T[capacity])_capacity(capacity),_size(0){}void puch_back(const T x); //尾插void pop_back(); //尾删~Vector(); //析构时需要调用delete释放空间
private:T* _p;int _capacity;int _size;
};//在类模板外定义成员函数需要加上模版参数列表
templateclass T
VectorT::~Vector()
{if (_p ! nullptr){delete[] _p;_capacity _size 0;}
}值得注意的是和模板函数一样类模板并不是一个具体的类它只是一个模具只有进行实例化后才会变成一个具体的类。 4.2 类模版的实例化 与函数模板实例化不同类模板不支持隐式类型推导类模板实例化需要在类模板名字后用显式指定模板参数的实际类型。注意类模板的名字不是真正的类只有指定类型实例化后才是真正的类。
//模板的实例化
int main()
{//Vector是类名Vectorint才是类型名才能用来定义对象Vectorint vi(20); //用参数为int的Vector类定义对象Vectordouble vd(10); //用参数为double的Vector类定义对象return 0;
} 类模版经过类型实例化后得到的类我们称作模板类通过模板类我们就可以定义许多相应的类对象三者的关系可用下图表示 以上就是本期的全部内容啦
制作不易能否点个赞再走呢