c++模板(函数模板,类中函数模板,类模板)
作用:
减少程序中的冗余信息。如:多个函数或类的除了参数类型外,其余都完全相同时,可以使用模板来减少重复信息(参考函数重载时,输入参数数量也相同的情况)
1、函数模板
即建立一个通用函数,只不过该函数的返回类型和形参类型都不具体指定,其定义格式如下:
template <typename 类型名>
类型名或void 函数名(类型名 形参表)
{
函数体
}
或
template <class 类型名>
类型名或void 函数名(类型名 形参表)
{
函数体
}
注:
1、此处的类型名是由开发人员自己决定的。
2、一般不注重向后兼容且愿意输入较长的类型名时,选用typename。
代码示例:
#include <iostream>
#include <string>
using namespace std;template <typename ty_na>
ty_na func_name(ty_na* parameters, int size = 0) {ty_na first_num = parameters[size];return first_num;
}int main()
{int array_int[] = {1,2,3,4,5};int first_num = func_name(array_int, 0);cout << first_num << endl;return 0;
}
此外,由于函数模板也属于函数,因此也可以对其进行函数重载,重载时,参数和参数数量均可改变:
#include <iostream>
#include <string>
using namespace std;template <class type>
type func_name2(type a, type b)
{type c = a - b;return c;
}template <class type>
type func_name2(type x, type b, type k)
{type y = k * x + b;return y;
}
int main()
{int get_c = func_name2(1, 2);double get_y = func_name2(2.0, 3.2, 2.0);cout << "get_c=" << get_c << endl;cout << "get_y=" << get_y << endl;
}
2、类中函数模板
2.1先在头文件的对应类中声明模板函数
class cls1
{
public:template<typename T>void func(T &args);
}
2.2在对应cpp文件中定义模板函数
template<typename T>void cls1::func(T &args){函数体}
3、类模板
3.1 基本概念
格式:
template <template 类型名>
class 类名
{
public:
类型名 成员数据
成员函数(函数类型名 参数名)
}
当类模板中的成员函数需要在类外定义时,格式为:
template <typename 类型名>
函数类型名 类名<类型名>::成员函数名(类型名 形参表) {...}
示例:
#include <iostream>
#include <string>
using namespace std;template <typename num>
class compute
{
public:num a, b;compute(num x, num y) :a(x), b(y) {};num add();
};
template <typename num>
num compute<num>::add(){return a + b;
}int main()
{compute<int> result(2, 3);cout << result.add() << endl;
}
此外,类模板可以对模板类型指定默认类型,如:
template <typename TYPE=int>
class CLS{...}
注意:必须使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型。当类模板有类型默认参数时,可以不实例化对应类型。
template <class Name_T,class Age_T = int>
class Person {
public:Person(Name_T name, Age_T age) {this->m_Name = name;this->m_Age = age;}void showPerson() {cout << "name:" << this->m_Name << " ";cout << "age:" << this->m_Age << endl;}private:Name_T m_Name;Age_T m_Age;
};int main() {//Person p1("马蒂", 22);//使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型Person<string, int> p1("马蒂", 22);p1.showPerson();Person<string> p2("诺顿", 78);//当类模板有类型默认参数时,可以不实例化对应类型p2.showPerson();system("pause");return 0;
}
3.2 类模板中成员函数的创建时机
一般类中的成员函数是一开始就创建,而类模板中的成员函数在调用时才会被创建。
如:下列代码可以生成成功,但在实际运行时必定会报错,这是因为类模板的成员函数在生成时并没有被创建,而发生调用后,才能被编译器检查到是否调用发生错误。
class P1 {
public:void func1() {cout << "P1" << endl;}
};class P2 {
public:void func2() {cout << "P2" << endl;}
};template <class T>
class TP {
public:T obj;void func3() {obj.func1();}void func4() {obj.func2();}
};int main() {TP<P1> p1{};p1.func3();p1.func4();system("pause");return 0;
}
3.3类模板实例化的对象作为函数参数
a)指定传入的类型,直接显示对象的数据类型。
b)将对象中的参数变成模板传入。
c)整个类模板化,将对象类型模板化进行传递。
template <class Name_T,class Age_T = int>
class Person {
public:Person(Name_T name, Age_T age) {this->m_Name = name;this->m_Age = age;}void showPerson() {cout << "name:" << this->m_Name << " ";cout << "age:" << this->m_Age << endl;}private:Name_T m_Name;Age_T m_Age;
};//指定传入的类型,直接显示对象的数据类型。
void func1(Person<string, int>& p) {p.showPerson();
}
//将对象中的参数变成模板传入。
template<class T1, class T2>
void func2(Person<T1, T2>& p) {p.showPerson();
}
//整个类模板化,将对象类型模板化进行传递。
template<class T_>
void func3(T_& p) {p.showPerson();
}
4、多类型模板
当需要返回的值的类型不确定时,可声明返回类型为auto(c++11),此时需要在函数体内使用decltype函数来获取返回值类型:
decltype(计算表达式) self_typename
示例:
auto Quick_func::get_max(T1& a, T2& b){decltype(a > b ? a : b) out = a > b ? a : b;cout << "out:" << out << endl;return out;
}int main()
{int a = 20;double b = 115.0;typedef decltype(a > b ? a : b) outtype;outtype out = get_max(a, b);}
5、类模板与继承
a)如果父类是类模板,子类必须指定父类的参数类型。
b)如果想要同样灵活使用的父类的参数,将子类定义为类模板,指定子类的参数类型,将其作为继承到的父类参数类型即可。
示例:
template <class T>
class Base {T num;
};//指定子类的参数类型
class Son1 :public Base<float> {};//灵活使用模板参数
template<class T1,class T2>
class Son2 :public Base<T1> {T2 son2_param;
};
6、类模板成员函数类外实现与分文件编写
6.1 定义
类外实现:
当类模板的成员函数在类内声明,类外进行实现时,在实现部分中,必须加上与类模板同样的template类型定义行,在普通类成员函数作用域的加上显示自定义类型使用,如:
template<class T>
void 类名<T>::函数名(T 形参)
{...}
分文件编写 :
由于类模板中的成员函数是在调用时才会生成,因此如果只include写有类模板成员函数声明的头文件会报错,无法链接到成员函数定义。
解决方法:
a)直接在调用该成员函数的文件中包含写有类模板成员函数定义的cpp文件。
b)将类模板成员函数定义和声明写在同一个文件中,并将文件后缀改为hpp。
6.2 示例
头文件:
template <class Name_T,class Age_T>
class Person {
public:Person(Name_T name, Age_T age);void showPerson();
private:Name_T m_Name;Age_T m_Age;
};
函数声明文件:
#include "head1.h"template<class Name_T,class Age_T>
Person<Name_T, Age_T>::Person(Name_T name, Age_T age) {this->m_Name = name;this->m_Age = age;
}template <class Name_T, class Age_T>
void Person<Name_T, Age_T>::showPerson() {cout << "name:" << this->m_Name << " ";cout << "age:" << this->m_Age << endl;
}
main函数文件:
#include "head1.h"
#include "func1.cpp"
int main() {Person<string, int>* p = NULL;p = new Person<string, int>("Adam", 23);p->showPerson();delete p;system("pause");return 0;
}
7、类模板友元
a)类模板中可以定义友元全局函数,从而直接使用类模板的自定义数据类型。
b)当只在类模板中声明友元全局函数时,由于编译顺序原因,需要把该友元全局函数定义在类模板的前面,才能让类模板中的友元声明实现,而与此同时,由于友元全局函数定义时,将类模板作为传入参数,需要在该函数定义前“声明”一下有该类模板的存在,否则不能完成函数定义。
template <class Name_T, class Age_T>
class Person;template <class T1, class T2>
void printPerson2(Person<T1, T2>& p) {cout << "name:" << p.m_Name << " ";cout << "age:" << p.m_Age << endl;
}template <class Name_T,class Age_T>
class Person {//类内友元friend void printPerson1(Person<Name_T, Age_T> &p) {cout << "name:" << p.m_Name << " ";cout << "age:" << p.m_Age << endl;}//类外实现友元template <class T1, class T2>friend void printPerson2(Person<T1, T2>& p);
public:Person(Name_T name, Age_T age);void showPerson();
private:Name_T m_Name;Age_T m_Age;
};
c++模板(函数模板,类中函数模板,类模板)相关推荐
- 类中函数模板 typeof_Julia中的typeof()函数
类中函数模板 typeof Julia| typeof()函数 (Julia | typeof() function) typeof() function is a library function ...
- python类中函数互相调用记得带self
import time from selenium import webdriver import pymysql import uuid class main (object): def __i ...
- MFC类中获得其它类指针
MFC类中获得其它类指针 从视图类获得文档类的指针是很容易的,用GetDocument即可,然而只能从视图类获得文档类的指针是远远不够的,每个类都有获得其它各个类指针的一套方法,本文归纳如下 AD: ...
- 重贴:MFC类中获得其它类指针 (转)
重贴:MFC类中获得其它类指针 (转)[@more@] MFC类中获得其它类指针 成都:苏颖锋 (vcmfc输入并转贴) 当用VC++的Application Wizard生成除了CDialog Ba ...
- python中自定义类中的self_Python类和构造方法
1.面向对象介绍 描述:是函数的一个变种,在Python中,有函数式编程和面向对象编程,java和C#之类只能把函数写到类里,没有函数式编程,所以只有面向对象,所以在Python中有了选择,可能就变得 ...
- 类中定义自身类的对象
在C++的类定义中,是不能够在类中定义自身类的对象的,但是可以定义自身类的指针对象和引用. class A { public: A () { cout<<"Constru ...
- PetShop 4.0知识点:base 关键字用于从派生类中访问基类的成员
//base 关键字用于从派生类中访问基类的成员: //调用基类上已被其他方法重写的方法. //指定创建派生类实例时应调用的基类构造函数. //基类访问只能在构造函数.实例方法或实例属性访问器中进行. ...
- python中arcsec_在Python类中继承Cython类
我有两个用cython编写的类,我想在python中的一个类中使用它们.在 位置.pyximport numpy as np cimport numpy as np cimport cython cp ...
- string类有可以调换方向的函数吗_C++中的string类的用法小结
相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有没有这样使用起来非常方便的类呢?答案是肯 ...
最新文章
- Python 的练手项目有哪些值得推荐?
- Infopath重复表分页(原创)
- 【商务智能】商务智能 ( 概念 | 组成 | 过程 )
- Unity开发者如何有效地进行本土化
- PCM设备能在公网使用吗?
- 【生成器】PHP的生成器yield【原创】
- 第四期coding_group笔记_用CRF实现分词-词性标注
- OpenCV的第一个小程序:读取图像并显示
- JPYXGSIT故障解决方案
- linux未找到telnet命令
- 使用NVivo完善定性编码的艺术
- 主板android刷机,安卓主板刷机步骤
- 做互联网最重要的是希望! 【水木周平】
- 数据结构之树家族介绍
- 哪款立体声骨传导蓝牙耳机好,推荐几款目前主流的骨传导耳机
- 基于JAVA中小学教师培训管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
- 17.Rust中函数式语言功能:迭代器与闭包
- XCP实战系列介绍16-XCP标定过程指令解析
- 使用HorizontalListView仿车来了公交时刻表
- bravado哺乳内衣 这款哺乳胸罩,越早买越好,别等到下垂涨奶才知道后悔!
热门文章
- 下载!《Nacos 架构与原理》pdf
- python编程:从入门到实践(持续更新)
- C++产生随机数函数rand()
- 多线程相关实例(多线程经典应用场景)
- 拼多多商品详情接口,拼多多详情页接口,宝贝详情页接口,商品属性接口,商品信息查询,商品详细信息接口,h5详情,拼多多APP详情
- Verification和Validation
- 干货 | 深度学习之卷积神经网络(CNN)的模型结构
- 软件测试黑盒测试代码,软件测试黑盒测试代码.doc
- java登陆界面背景_Java登录界面的实现(注册、登录、背景图片)
- oracle数据库impdp命令的使用方法