团队网站建设,哪些网站做的不好,自己做的网站点进去很卡,深圳建设交易公司C模板初阶泛型编程函数模板概念函数模板格式函数模板原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化泛型编程
我们前面学习了C的函数重载功能#xff0c;那么我们如何实现一个通用的交换函数呢#xff0c;比如:我传入int就是交换int#xff…
C模板初阶泛型编程函数模板概念函数模板格式函数模板原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化泛型编程
我们前面学习了C的函数重载功能那么我们如何实现一个通用的交换函数呢比如:我传入int就是交换int传入double就进行double类型的交换……
void Swap( int a, int b)
{int temp a;a b;b temp;
}
void Swap(double a, double b)
{double temp a;a b;b temp;
}
void Swap(char a, char b)
{char temp a;a b;b temp;
}
void Swap(int* a, int* b)
{int* temp a;a b;b temp;
}我们可以发现尽管有了函数重载的技术但是我们还是避免不了所有问题我们很难写出一个通用的Swap函数如果我们每增加一个新类型我们就得重新写一个Swap函数很麻烦那么有没有什么办法让我只写一份通用的代码所有类型都可以用呢当然有对于C语言的这种不足C在此基础上提出了泛型编程的概念就是对于一些所有类型都可通用的代码比如Swap这种我们在写具体实现的时候可以假装我们的数据类型是通用的然后在对其进行处理当我们在调用该函数的时候编译器会自动推演出数据的具体类型这就好比我们在写方程一样我们先假设未知数将未知数先当成已知最后在解出未知数这里自动推演数据类型的过程就相当于在解方程
这个编写通用代码的过程就是在造模子通过给这个模子传递不同的参数类型来确定具体的数据类型从而获得具体类型对应的代码生成具体类型代码的过程是由编译器来帮助我们完成的我们无需在自己手动写了
在C中模板是泛型编程的基础 模板又分为函数模板、类模板
函数模板
概念
函数模板代表了一个函数家族该函数模板与类型无关在使用参数时由编译器根据所传参数类型自动推演函数参数的具体类型由此产生特定类型的函数版本这个过程被称为实例化
函数模板格式 templateclass 类型参数名1class 类型参数名2…… 返回类型 函数名(参数列表) 或者 templatetypename 类型参数名1,typename 类型参数名2……; 返回类型 函数名(参数列表) 注意typename是用来定义模板参数的关键字class也可以但是struct不可以 实例写一个通用的交换函数
template typename T
void Swap(T a, T b)
{T tmp a;a b;b tmp;
}函数模板原理
么如何解决上面的问题呢大家都知道瓦特改良蒸汽机人类开始了工业革命解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么重复的工作交给了机器去完成。有人给出了论调懒人创造世界。 函数模板是一个蓝图它本身并不是函数是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器; 函数模板的实例化
用不同类型的参数使用函数模板时称为函数模板的实例化。模板参数实例化分为隐式实例化和显式实例化 1、隐式实例化 上述Add的调用就是隐式实例化编译器会根据我们传递给Add的参数自动推演出类型参数的具体类型以此来生成具体类型的交换函数来给我们用 当然我们不能乱传递参数类型比如Add(a,x); 编译器在调用该Add函数的时候根据左参数类型先推演出类型参数T为int类型然后又根据有参数类型推演出类型参数T为double类型那么参数类型到底具体为那个类型这就会让编译器陷入歧义编译器也就会报错Add函数也就无法正确实例化类型参数会根据以第一次推演出的结果作为默认类型与auto在一排的用法差不多但是模板无法完成参数的隐式转换! 那如果我们就是要调用Add(a,x);函数应该怎么办 有两种解决办法 1、强转a或强转x就是将ax的类型转换成一致的 2、显示实例化 2、显示实例化 就是明确指定类型参数的具体类型不需要编译器再根据参数类型自动推演了明确指定参数的具体类型过后编译器就会自动生成具体函数来供调用处使用 比如上述的Add(a,x) 我们像这样做:Addint(a,x);显示的指定类型参数为int编译器就会自动生成参数类型为int的Add函数 如果类型不匹配编译器会自动尝试隐式转换无法完成完成隐式类型转换的编译器直接报错 这里的隐式类型转换与上面隐式调用的类型转换不一样这里使明确规定了类型参数的具体类型也就是先生成了具体函数才有的隐式类型转换上面是根据参数类型推演类型参数的具体类型然后再生成匹配的函数参数不匹配无法生成具体函数怎么能进行隐式转换呢 模板参数的匹配原则 1、非模板函数与函数模板同名同时函数模板还可以实例化成非模板函数编译器会优先调用非模板函数 为什么会出现这种情况呢 编译器是很聪明的如果我们去调用函数模板时编译器会首先根据参数类型推演出类型参数的具体类型然后实例化出具体的Add函数来调用你看啊现在我明明有现成的Add函数可以用那么我们为什么还要去实例化再调用呢这不是脱了裤子放屁多此一举嘛 那如果我们非要调用模板实例化出来的Add函数该怎么办呢 当然是显示调用 2、对于非模板函数与同名函数模板其他条件都相同但是非模板函数的参数类型与调用处的类型不一样编译器会根据函数模板实例化出最匹配的函数来调用 3、对于隐式实例化函数模板不会发生隐式类型转换对于显示实例化函数模板可以发生隐式类型转换 类模板
类模板的定义格式 templateclass T1,class T2,class T3,…… class 类模板名 { //类成员定义 }; 比如现在我们写一个栈类模板
template class T
class Stack
{Stack(){int capacity 4;_a new T[capacity];_top 0;_capacity capacity;}~Stack(){delete[] _a;_top _capacity 0;}
private:T* _a;int _top;int _capacity;
};类模板中的成员函数全是模板函数 然后注意此时的Stack不是具体的类而是编译器根据被实例化的类型生成具体类的模具 同时类模板的成员函数也可以实现在类内声明类外定义 只不过与我们平时写的具体的类的定义方式不太一样 比如现在我在类内声明构造函数类外定义构造函数 这样我们既能定义基本数据类型为double的栈也可以定义基本数据类型为int的栈了 这时候或许会有读者说我用typedef也能做到类型替换啊可是typedef不能做到Stackint与Stackdouble两种栈同时存在啊如果想要这两个栈同时存在我们就只能再重新定义一个栈这样很是麻烦 同时不建议类模板的声明与函数定义分离 类模板的实例化
类模板的实例化与函数模板的实例化不同类模板实例化只能通过显示实例化不能隐式实例化