福建省网站建设有限公司,自己做的产品在哪个网站上可从卖,淘宝客网站一定要备案吗,装修平台网站排名前十名前言 在学习C的模版之前#xff0c;咱们先来说一说模版的概念#xff0c;模版在我们的日常生活中非常常见#xff0c;比如我们要做一个ppt#xff0c;我们会去在WPS找个ppt的模版#xff0c;我们只需要写入内容即可#xff1b;比如我们的数学公式#xff0c;给公式套值的模版之前咱们先来说一说模版的概念模版在我们的日常生活中非常常见比如我们要做一个ppt我们会去在WPS找个ppt的模版我们只需要写入内容即可比如我们的数学公式给公式套值就可以算出结果比如我们在写实验报告老师会给一个实验报告的模版我们按照里面的模版直接写入内容即可所以生活中的模版就是相当于提供了一个事物的框架我们只需要输入主要的内容就行了。那C里面的模版也是如此了解到了这里就一起开始学习C的模版吧 一、函数模版 我们在C上学过一个函数重载函数重载就是通过形参类型的不同他们被分为不同的函数虽然函数名相同比如我们要实现一个交换函数如下代码 void Swap(int a, int b)
{int tmp a;a b;b tmp;
}
void Swap(double a, double b)
{double tmp a;a b;b tmp;
}
void Swap(char a, char b)
{char tmp a;a b;b tmp;
} 我们会发现这作为一个交换函数未免也太麻烦了吧虽然可以实现不同类型的参数的交换但是这样的代码多少回会显得冗余(多余)基于这样的原因C创造了函数模版。 1. 函数模版的定义 函数模版代表了一个函数家族该函数模板与类型无关在使用时被参数化根据实参类型产生函数的特定类型版本。 如何理解这句话呢其实就是我给你一个函数的模版比如交换函数的模版你只需要填入实参的不同类型编译器自动识别给你匹配相应的函数。 其实这属于一种泛型编程泛型编程指的就是编写与类型无关的通用代码具有通用性而模版是泛型编程的基础 2. 函数模版的格式 template 指的是模版要写函数模版之前必须要指定模版的参数类型也就是说T代表的就是模版T就是可以换成任何数据类型的而class / typename 是定义模版参数的关键字可以在定义多个模版参数用逗号分开即可。 下面的代码就是一个函数模版我们要实现一个交换函数那要设计的模版是谁呢因为不同的类型都要实现交换所以我们的模版参数要放到形参的位置上让我们在传不同类型的实参时可以顺利完成对应的交换。 其中template class T中的T是虚拟类型 #include iostream
using namespace std;
templateclass T
void Swap( T left, T right)
{T temp left;left right;right temp;
}
int main()
{int a 3;int b 4;Swap(a, b);double c 2.5;double d 6.6;Swap(c, d);char ch1 x;char ch2 y;Swap(ch1, ch2);cout a b endl;cout c d endl;cout ch1 ch2 endl;return 0;
}在调用函数的时候直接传我们想交换的元素就可以剩下的都是编译器做的事情。所以我们本来针对不同的数据类型要实现不同的函数重载但有了函数模版之后我们就只需要写一个函数了剩下的是编译器帮我们完成的。不得不感慨一下真的是懒人创造世界 3. 函数模版的图示 在编译器编译阶段对于模板函数的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供 调用。比如当用double类型使用函数模板时编译器通过对实参类型的推演将T确定为double类型然 后产生一份专门处理double类型的代码对于字符类型也是如此。 4. 模版参数的实例化 函数模版的实例化也就是相当于去调用这个函数模版我们上面看到的是模版参数是在形参这里的那如果我们没有在形参中使用模版参数呢这样如何告诉模版参数是什么数据类型呢所以在函数模版的实例化分为显式实例化和隐式实例化 4.1 隐式实例化 隐式实例化就是并没有在函数调用的时候明确指出模版参数的数据类型比如下面的代码 #include iostream
using namespace std;
templateclass T
void Swap( T left, T right)
{T temp left;left right;right temp;
}
int main()
{int a 3;int b 4;Swap(a, b);return 0;
}
4.2 显式实例化 显式实例化就是在函数调用时显式的写出了模版参数的数据类型如下图代码 #include iostream
using namespace std;
templateclass T
void Swap( T left, T right)
{T temp left;left right;right temp;
}
int main()
{int a 3;int b 4;Swapint(a, b);return 0;
} 大家可能会觉得这个显式实例化好像挺多余的因为我们在函数传参的时候就已经隐式的传递了模版参数的数据类型了那大家再来看下面的代码 #include iostream
using namespace std;
templateclass T
T GetNum(int n)
{T b n;return b;
}
int main()
{int a 3;int b 4;int c GetNum(a);return 0;
} 如果我们没办法从传参这里让编译器得知模版参数的数据类型呢我们这样写是不对的所以我们不能隐式的传了。必须显式的写正确的代码如下 #include iostream
using namespace std;
templateclass T
T GetNum(int n)
{T b n;return b;
}
int main()
{int a 3;int b 4;int c GetNumint(a);return 0;
} 所以这种情况我们必须显式实例化里面就是告诉模版参数的数据类型。 5. 如何应对不同数据类型的运算 如果我们要实现一个int和double进行加法我们下面代码还可以实现吗 #include iostream
using namespace std;
templateclass T
T Add(const T a, const T b)
{return a b;
}
int main()
{int a 3;double b 4.7;cout Add(a, b) endl;return 0;
} 我们要记住对于模版函数不允许类型转换的所以a是int类型先传入给TT就是int类型又因为不会类型转换所以会报错的。那应该如何实现呢我们直接给出最优方案 #include iostream
using namespace std;
templateclass T, class Y
Y Add(const T a, const Y b)
{return a b;
}
int main()
{int a 3;double b 4.7;cout Add(a, b) endl;return 0;
} 我们只需要加一个模版参数就可以了但是要知道返回值的类型必须是类型提升最后的类型这是什么意思呢 因为不同类型的运算会发生类型的提升 char —— int —— float —— double 所以要记住这里就OK了 6. 模版参数的匹配规则
1、 合适匹配的情况下有现成的就匹配现成的2、没有合适的就将就用指没有函数模版的时候3、有更合适就用更合适的哪怕要自己使用函数模版创造
二、类模版
1. 类模版的格式 其实也跟函数模版差不多就是我们要知道的是模版参数给谁就行其他的都不动。 template class T
class Stack
{
public:Stack(int capacity 4): _a(new T[capacity]), _size(0), _capacity(capacity){}~Stack(){delete []_a;_a nullptr;_size _capacity 0;}
private:T *_a;int _size;int _capacity;
};
2. 类模版的类名、类类型和类模版的实例化 这里想说的是我们定义了类模版之后类名是什么类类型是什么类模版又是如何实例化的呢 Stackint st; 上面的代码是正确调用这个类那类名还是Stack而这个类模版的类类型就不是类名类 而类名显式实例化模版参数 #include iostream
using namespace std;
template class T
class Stack
{
public:Stack(int capacity 4): _a(new T[capacity]), _size(0), _capacity(capacity){}~Stack(){delete []_a;_a nullptr;_size _capacity 0;}
private:T *_a;int _size;int _capacity;
};
int main()
{Stackint st;return 0;
}
3. 在类模版外的函数定义 这里需要重点注意一下我们函数定义可以在类内部也可以在类外部但是在类外部需要注意一下简单的规则。 1. 类模版外的函数定义必须在同一个文件里 2. 需要指定域空间和模版 #include iostream
using namespace std;template class T
class Stack
{
public:Stack(int capacity 4): _a(new T[capacity]), _size(0), _capacity(capacity){}~Stack();
private:T *_a;int _size;int _capacity;
};templateclass T
StackT::~Stack()
{delete []_a;_a nullptr;_size _capacity 0;
}int main()
{Stackint st;return 0;
}
三、使用模版的注意事项
1. 模板运行时不检查数据类型也不保证类型安全相当于类型的宏替换
2. 模板与类型无关提高了代码复用性
3. 只要支持模板语法模板的代码就是可移植的也就是可移植性好跨平台性
4. 类模板是一个类家族模板类是通过类模板实例化的具体类
5. 类模板的成员函数都是模板函数