C++模板的注意事项

函数模板

template <typename T>        //把typename换成class也可以

函数模板调用方法

使用过程中, 有两种方法调用, 如下:

  • 自动类型推导:
#include <iostream>template <class T>
void swap(T &first, T &second) {T temp;temp = first;first = second;second = temp;
}int main() {int a = 10;int b = 20;swap(a, b);return 0;
}
  • 显示指定类型
#include <iostream>template <class T>
void swap(T &first, T &second) {T temp;temp = first;first = second;second = temp;
}int main() {int a = 10;int b = 20;swap<int>(a, b);return 0;
}

注意, 两者的区别在于调用时是否传入模板类型.

函数模板调用规则

  • 普通函数调用时可以发生隐式类型转换
  • 函数模板, 用自动类型推导, 不能发生隐式类型转换
  • 函数模板, 用显示指定类型, 可以发生隐式类型转换 

普通函数和函数模板调用顺序规则

假设有以下例子:

#include <iostream>
using namespace std;void mSwap(int &first, int &second) {cout << "call normal function" << endl;int temp;temp = first;first = second;second = temp;
}template <class T>
void mSwap(T &first, T &second) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp;
}
  • 如果函数模板和普通函数都可以调用, 优先调用普通函数

示例代码:

int main() {int a = 10;int b = 20;mSwap(a, b);return 0;
}

结果:

 

  • 可以通过空模板参数列表强制调用函数模板

示例:

int main() {int a = 10;int b = 20;mSwap<>(a, b);return 0;
}

结果:

  • 函数模板可以发生函数重载

比如又加了一个函数:

template <class T>
void mSwap(T &first, T &second) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp;
}template <class T>
void mSwap(T &first, T &second, T &third) {cout << "call template function" << endl;T temp;temp = first;first = second;second = temp;
}

现在就有两个同名函数模板了, 这样传入三个参数就会调用下面的. 

  • 如果函数模板可以产生更好的匹配(不需要发生隐式类型转换), 优先调用函数模板

比如有如下调用:

int main() {char a = 'a';char b = 'b';mSwap(a, b);return 0;
}

运行结果为:

函数模板局限性

比如有如下代码:

class People {
public:People(string name, int age) : m_name(name), m_age(age) {}string m_name;int m_age;
};template <class T>
bool mCompare(const T &a, const T &b) {if (a == b)return true;elsereturn false;
}

 当有如下调用时:

int main() {People p1("michael", 18);People p2("michael", 18);mCompare(p1, p2);return 0;
}

会发生如下编译错误:

出现以上情况我们当然可以在类中实现" == "的运算符重载, 也可以用如下的方法, 在以上代码的基础上增加以下代码:

template<> bool mCompare(const People &a, const People &b) {if (a.m_name == b.m_name &&a.m_age  == b.m_age)return true;elsereturn false;
}

这样即对以上的函数模板进行people定制化重载。

类模板

在类的声明按照如下声明:

template <class nameType, class ageType>
class People {
public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age;
};

这样使用的时候按照如下使用:

int main() {People<string, int> p1("michael", 18);return 0;
}

类模板中成员函数创建时机

类模板中成员函数在调用时才创建.

如下测试代码:

class People1 {
public:void showPerple1(){cout << "this is class People1" << endl;}
};class People2 {
public:void showPerple2(){cout << "this is class People2" << endl;}
};template <class T>
class mClass {
public:void show1() {m_obj.showPerple1();}void show2() {m_obj.showPerple2();}T m_obj;
};

如上代码是可以编译通过的.

如下测试代码:

int main() {mClass <People1> p1;mClass <People2> p2;p1.show1();p2.show2();return 0;
}

 编译时候确定了T的类型之后, 如果发现T中没有成员函数中的函数, 就会报错.

类模板的对象作函数参数

假设有如下模板类:

template <class nameType, class ageType>
class People {
public:People(const nameType &name, const ageType &age) : m_name(name), m_age(age) {}void show() {cout << "name: " << m_name << endl;cout << "age: " << m_age << endl;}nameType m_name;ageType  m_age;
};

如果想要调用People实例化对象的show函数, 可以有以下方法:

  • 指定传入类型

方法如下:

void showPeople1(People<string, int> &p) {p.show();
}int main() {People<string, int> p1("michael", 18);showPeople1(p1);return 0;
}
  • 参数模板化

方法如下:

template <class nameType, class ageType>
void showPeople2(People<nameType, ageType> &p) {p.show();
}int main() {People<string, int> p2("michael", 18);showPeople1(p2);return 0;
}
  • 整个类模板化

方法如下:

template <class P>
void showPeople3(P &p) {p.show();
}int main() {People<string, int> p3("michael", 18);showPeople3(p3);return 0;
}

类模板继承

  • 当父类是模板类时, 子类在继承的时候需要指定父类中的模板类型, 当有如下代码:
template <class T>
class Father {
public:T m_T;
};class Son : public Father {
public:
};

这样编译会报错, 需要改为:

template <class T>
class Father {
public:T m_T;
};class Son : public Father<int> {
public:
};

这样就可以了 

  • 也可以把子类也变成模板类, 可以按照如下操作:
template <class T>
class Father {
public:T m_T;
};template <class T1, class T2>
class Son : public Father<T2> {
public:T1 m_T1;
};

类外实现

当有如下类:

template <class nameType, class ageType>
class People {
public:People(nameType name, ageType age);void showPeople();nameType m_name;ageType m_age;
};

当我们在类外实现其构造函数和成员函数时, 需要按照如下方式:

//constructor
template <class nameType, class ageType>
People<nameType, ageType>::People(nameType name, ageType age) {m_name = name;m_age = age;
}//member function
template <class nameType, class ageType>
void People<nameType, ageType>::showPeople() {cout << "name: " << m_name << endl;cout << "age: " << m_age << endl;
}

类模板的分文件编写

类模板与友元

函数模板和类模板的区别

  • 类模板是不存在类型推导的, 所以实例化对象的时候必须传入类型.
  • 类模板是可以有默认参数的

可参考如下代码:

template <class nameType, class ageType = int>
class People {
public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age;
};int main() {People<string> p1("michael", 18);return 0;
}

这样是可以的.

如果两个参数都有默认类型, 实例化对象的时候也必须要有尖括号, 如下: 

template <class nameType = string, class ageType = int>
class People {
public:People(nameType name, ageType age) : m_name(name), m_age(age) {}nameType m_name;ageType m_age;
};int main() {People <>p1("michael", 18);return 0;
}

模板的特化

模板的设计是为了有效减少代码量,但是某些情况,对于某种特定类型,模板就需要进行特化。

全特化和偏特化

全特化就是限定死模板实现的具体类型,偏特化就是如果这个模板有多个类型,那么只限定其中的一部分。

函数模板的特化

函数模板只能进行全特化不能进行偏特化,函数模板的全特化可以参照上文说的,正常函数就是相当于对函数模板的全特化。

类模板的特化

template<typename T1, typename T2>
class Test
{
public:Test(T1 i,T2 j):a(i),b(j){cout<<"模板类"<<endl;}
private:T1 a;T2 b;
};template<>
class Test<int , char>
{
public:Test(int i, char j):a(i),b(j){cout<<"全特化"<<endl;}
private:int a;char b;
};template <typename T2>
class Test<char, T2>
{
public:Test(char i, T2 j):a(i),b(j){cout<<"偏特化"<<endl;}
private:char a;T2 b;
};

那么下面3句依次调用类模板、全特化与偏特化:

Test<double , double> t1(0.1,0.2);  
Test<int , char> t2(1,'A');  
Test<char, bool> t3('A',true);  
//依次打印:
//类模板
//全特化
//偏特化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/505448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

excel教程自学网_Excel自学教程:万能查找函数Lookup的神应用和技巧

提起查找函数&#xff0c;大家第一时间想到的肯定是Vlookup&#xff0c;其实大多数人不知道&#xff0c;Lookup才是查找函数之王&#xff0c;它几乎能高效地实现Vlookup函数的所有功能&#xff0c;部分功能是Vlookup函数无法比拟的。一、语法结构和基本使用方法。应用场景&…

C++ STL 容器的一些总结

1 C STL类型及实现原理 1.1 顺序容器 容器中的元素为有序排列,可以指定元素插入位置. 1.1.1 vector 顺序存储, 初始化过程会分配一定量空间, 在尾部插入会很快, 但是在中间插入元素, 会把之后所有元素向后平移, 所以较慢(中间删除元素同理). 如果元素个数超过当前限制, 会重…

java电商项目简历_一文解析从写简历,到面试、谈薪酬技巧和防坑指南

点击上方“码农沉思录”&#xff0c;选择“设为星标”优质文章&#xff0c;及时送达读者大大们好&#xff0c;好几天没更新了。一方面因为这几天工作忙&#xff0c;占了写作的时间。另一方面是在准备这篇文章各种素材&#xff0c;今年是最难求职年&#xff0c;我希望通过这篇文…

qq浏览器极速版_安卓手机QQ轻聊版大升级,极速版正式上线:无广告/省内存

8月28日&#xff0c;安卓手机QQ极速版推出了4.0正式版&#xff0c;采用了全新的界面设计&#xff0c;仅保留了基本聊天功能和QQ空间、小程序、钱包、文件等少量QQ主推功能&#xff0c;现已开放下载&#xff0c;QQ极速版安装之后会覆盖QQ轻聊版。QQ极速版4.0界面焕新升级&#x…

C++ STL 容器 vector

1 vector简介 顺序存储, 初始化过程会分配一定量空间, 在尾部插入会很快, 但是在中间插入元素, 会把之后所有元素向后平移, 所以较慢(中间删除元素同理). 如果元素个数超过当前限制, 会重新分配更大空间, 再把原容器中所有元素都拷贝到新的容器中. 优点: 支持随机访问(用下标…

3dmax卸载工具_3dmax软件如何彻底卸载?

近期有很多学员遇到关于3dmax软件卸载的问题&#xff0c;有的是想安装更高版本但不知道如何卸载更安全&#xff0c;有的是自己卸载了之后再安装其他版本却总是无法成功&#xff0c;这对此类问题&#xff0c;今天我做一个详细讲解&#xff1b;根据自己所遇问题&#xff0c;找到最…

华为app安装失败与已安装签名_手机APP为什么总是安装失败

整天“机不离手”的我们每个人手机里都装有好几十个APP但安装的时候总会出现跳出手机APP无法安装或安装失败的页面这究竟是怎么回事呢&#xff1f;小翼带你瞅瞅一、手机安全认证在安装或下载应用程序时&#xff0c;如果提示失败可能是因为系统“未知来源”没有开启。可以通过打…

C++ STL 中提供的算法

1 算法 1.1 for_each() 参数有三个: 首迭代器尾迭代器执行的函数 例如如下代码: #include <algorithm> //必须包含 #include <vector> using namespace std;int main() {vector<int> tmp;tmp.push_back(10);tmp.push_back(20);tmp.push_back(30);tmp.pu…

arma模型_GARCH模型应用:以国泰君安为例

1.下载国泰君安股票数据&#xff0c;计算对数收益率(1)首先安装包"quantmod"&#xff0c;这个包可以从雅虎财经的下载股票数据&#xff0c;具体包的解释见"【量化基础】R语言获取金融数据之quantmod包"。install.packages("quantmod")#安装包qua…

C++ STL 容器 string

1 string string内部含有一个char*字符串 2 string构造方式 无参构造 string str; 字符串构造 string str("abcd"); 拷贝构造n个相同字符 string str(10, k); //初始化为10个k 3 string赋值操作 可以有以下操作: void string_test() {string str1;str1 &qu…

小程序webview不全屏_小程序不在小(深度)

原标题&#xff1a;小程序不在小(深度)你问&#xff1a;“微信小程序适合哪些行业?”&#xff0c;回答是&#xff1a;“所有行业!”你可以想一下那些做过APP的公司&#xff0c;不管是任何行业的公司都可以拥有属于自己的APP&#xff0c;而从来不会有人问他们你们用的APP是否适…

leetcode 4 --- 寻找两个有序数组的中位数

1 题目 给定两个大小为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。 进阶&#xff1a;设计一个时间复杂度为 O(log (mn)) 的算法. 2 解法 这个题如果mn是偶数, 就是找到第(mn)/2以及第(mn)/2 1个数, 如果…

leetcode 142 --- linked-list-cycle-ii

1 题目&#xff1a; 对于一个给定的链表&#xff0c;返回环的入口节点&#xff0c;如果没有环&#xff0c;返回null 拓展&#xff1a; 你能给出不利用额外空间的解法么&#xff1f; 代码&#xff1a; class Solution { public:ListNode *detectCycle(ListNode *head) {} …

百度搜索引擎优化指南3.0_深圳网站搜索引擎排名优化电话,百度优化排名费用_华阳网络...

天津华阳在线科技有限公司为您详细解读深圳网站搜索引擎排名优化电话,百度优化排名费用的相关知识与详情&#xff1a;网站的主页标题是百度SEO的关键。你想要的主要关键词应该反映在标题中。如果标题写得好&#xff0c;百度很快就收录进去了。但要记住&#xff0c;有一点&#…

C++ STL 容器的一些总结 --- set(multiset)和map(multimap)

1 set和multiset 1.1 插入元素方式 set只能用insert插入数据. insert返回值是一个pair<iterator, bool>, 即插入数据的迭代器以及是否插入成功, multiset返回的只有迭代器, 因为不会插入失败. 1.2 删除 set只能用erase, 可以传迭代器或者是值. 1.3 注意事项 不允许…

苹果自带相册打马赛克_剪映app怎么给视频局部打马赛克

剪映app怎么给视频局部打马赛克呢&#xff1f;很多用户对此还不是很清楚&#xff0c;小编这里就给大家带来有关剪映app怎么给视频局部打马赛克的回答&#xff0c;希望能够对大家有所帮助。1、首先打开剪映app&#xff0c;进入首页后点击开始创作选项&#xff0c;2、这时选择需要…

excel表格如何转换成word表格_如何将excel转换成pdf?excel表格可以变成pdf文件吗?...

文字使用word&#xff0c;数据使用Excel&#xff0c;这应该是咱们日常生活中的一个规律了吧&#xff1f;不过不管是word文档还是Excel文档&#xff0c;都是可以被编辑修改的&#xff0c;那么我们怎么才能让它变得不能被编辑修改呢&#xff1f;小编这里还真有一个好方法&#xf…

python车牌识别系统开源代码_天津谁做车牌识别系统供应商,伸缩栅栏门_郑州荣锋科技有限公司...

首页 > 新闻中心发布时间&#xff1a;2020-11-13 22:54:57 导读&#xff1a;郑州荣锋科技有限公司为您提供天津谁做车牌识别系统供应商,伸缩栅栏门的相关知识与详情&#xff1a; (1)门处于关闭状态&#xff0c;控制器应骆动执行电机以佳速度曲线打开门;圆弧形自动门卷帘门机…

收发一体超声波测距离传感器模块_一文了解超声波液位计

为什么选择超声波液位计&#xff1f;因为&#xff0c;超声波液位计由声波的发射和接收之间的时间来计算传感器到被测物体的距离。无机械可动部分&#xff0c;可靠性高&#xff0c;安装简单、方便&#xff0c;属于非接触测量&#xff0c;且不受液体的粘度、密度等影响精度比较低…

什么牌子的平板电脑好_平板电脑什么牌子好?带你一探年度最佳平板的奥秘

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以免费收到最新内容了。每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。声明&#xff1a;本文转载自网络&#xff0c;如有侵权&#xff0c;请在后台留言联系…