C++进阶-1-模板基础(函数模板、类模板)
C++进阶 模板
1.1 函数模板
1 #include<iostream>
2 using namespace std;
3
4 // 模板
5
6 // 模板的简单实例
7 // 要求:
8 // 1.利用函数模板封装一个排序函数,可以对不同数据类型数组进行排序
9 // 2.排序规则由大到小,排序算法为:选择排序
10 // 3.分别利用char数组和int数组进行测试
11
12 // 交换函数模板
13 template<class T>
14 void mySwap(T& a, T& b) {
15 T temp = a;
16 a = b;
17 b = temp;
18 }
19
20 // 排序算法模板
21 template<class T> // 也可以写typename
22 void mySort(T arr[], int len) {
23 // 选择排序
24 for (int i = 0; i < len; i++) {
25 int max = i; // 认定最大值下标
26 for (int j = i + 1; j < len; j++) {
27 // 认定的最大值 比 遍历出的最大值 要小,说明 j 下标的元素才是真正的最大值
28 if (arr[max] < arr[j]) {
29 max = j; // 更新最大值下标
30 }
31 }
32 if (max != i) {
33 // 交换下标为max和i的元素
34 mySwap(arr[max], arr[i]);
35 }
36 }
37 }
38
39 // 打印数字内容模板
40 template<class T>
41 void printArray(T arr[], int len) {
42 for (int i = 0; i < len; i++) {
43 cout << arr[i] << " ";
44 }
45 cout << endl;
46 }
47
48
49 void test01() {
50
51 // 测试数组 char类型
52 char charArr[] = "badcfe";
53 int num_charArray = sizeof(charArr) / sizeof(char);
54 mySort(charArr, num_charArray);
55 printArray(charArr, num_charArray);
56
57 // 测试数组 int类型
58 int intArray[] = { 1, 3, 2, 6, 4, 5, 7 };
59 int num_int = sizeof(intArray) / sizeof(int);
60 mySort(intArray, num_int);
61 printArray(intArray, num_int);
62 }
63
64 int main() {
65
66 test01();
67
68 system("pause");
69
70 return 0;
71 }
72
73 // 总结
74 // C++除了面向对象编程思想外,还有 泛型编程 以及 STL 技术
75 //
76 // 模板:建立通用的模具,大大提高代码的复用性
77 // 模板不可以直接使用,它只是一种框架
78 // 模板的通用并不是万能的
79 //
80 // 模板分为:函数模板与类模板
81 //
82 //
83 // 函数模板:
84 //
85 // 模板的作用:建立一个通用函数,其函数返回值类型和形参类型都可以不具体制定,用一个虚拟的类型来表示
86 // 语法:
87 // template<typename T> // typename也可以写成 class
88 // 函数生命或定义
89 // 解释:T 通用的数据类型,名称可以替换,通常为大写字母
90 //
91 // 函数模板的使用方式有两种:自动类型推导、显示指定类型
92 //
93 // 模板注意事项:
94 // 1.自动类型推导方式,必须推导出一致的数据类型T,才可以使用
95 // 2.模板必须要确定出T的数据类型,才可以使用
96 //
97 // 普通函数与函数模板的区别
98 // 1.普通函数调用可以发生自动类型转换(隐式转换);
99 // 2.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
100 // 3.如果利用显示指定类型的方式,可以发生隐式转换;
101 //
102 // 所以,建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型
103 //
104 // 普通函数与函数模板的调用规则
105 // 1.如果函数模板和普通函数都有可以实现,编译器会优先调用普通函数
106 // 2.可以通过空模板参数列表来强制调用函数模板(加<>)
107 // 3.函数模板也可以发生重载
108 // 4.如果利用函数模板可以产生更好的匹配,优先调用函数模板
109 //
110 // 所以,既然提供了函数模板,就最好不要再提供普通函数了,否则出现二义性
111 //
112 // 模板的局限性
113 // 1.模板的通用型不是万能的
114 // 利用具体化的模板,可以解决自定义类型的通用化
115 // 学习模板不是为了写模板,而是在STL能够运用系统提供的模板
116 //
117
1.2 类模板
#include<iostream>
#include<string>
using namespace std; // 类 模板 // 示例1
//template<class Nametype, class Agetype> // 类模板可以有默认参数
template<class Nametype, class Agetype = int>
class Person1 {
public: Person1(Nametype name, Agetype age) {
this->m_Name = name;
this->m_Age = age;
} void showPerson() {
cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
} //string m_Name;
//int m_Age; Nametype m_Name;
Agetype m_Age; }; void test01() { //Person p1("Tom", 19); // 报错,无法自动推导类型
//Person1<string, int> p1("Tom", 19);
Person1<string> p1("Tom", 19); p1.showPerson(); } // 示例2
// 类模板对象做函数参数,三种传入方式 template<class T1, class T2>
class Person2
{
public:
Person2(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}; void showPerson() {
cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
} T1 m_Name;
T2 m_Age; }; // 1.指定传入类型
void printPerson1(Person2<string, int>& p) {
p.showPerson();
} // 2.参数模板化
template<class T1, class T2>
void printPerson2(Person2<T1, T2>& p) {
p.showPerson();
// 看一下编译器推导出的类型
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
} // 3.整个类模板化
template<class T>
void printPerson3(T& p) {
p.showPerson();
cout << "T的类型为:" << typeid(T).name() << endl;
} void test02() {
Person2<string, int>p("小明", 20); // 1.指定传入类型(最常用)
printPerson1(p); // 2.参数模板化
printPerson2(p); // 3.整个类模板化
printPerson3(p);
} // 示例3 类模板与继承
template<class T>
class Base {
T m;
}; // class Son:pubic Base // 错误,C++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son1 :public Base<int> { // 必须指定一个类型 }; // 如果想灵活制定出父类中T的类型,子类也需要变为模板
template<class T1, class T2>
class Son2 :public Base<T2> {
public:
Son2() {
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
T1 obj;
}; void test03() { Son1 s1; Son2<int, char> s2;
} // 示例4 类模板成员函数类外实现
template<class T1, class T2>
class Person4
{
public:
Person4(T1 name, T2 age); // 类内声明
//{
// this->m_Name = name;
// this->m_Age = age;
//}; void showPerson(); // 类内声明
//{
// cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
//} T1 m_Name;
T2 m_Age; }; // 类外实现
template<class T1, class T2>
Person4<T1, T2>::Person4(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
} template<class T1, class T2>
void Person4<T1, T2>::showPerson() {
cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
} void test04() {
Person4<string, int> p4("张三", 100);
p4.showPerson();
} int main() { // 类模板初识
//test01(); // 类模板对象做函数参数
//test02(); // 类模板与继承
//test03(); // 类模板成员函数类外实现
test04(); system("pause"); return 0;
} // 总结
//
// 模板分为:函数模板与类模板
//
//
// 类模板:
//
// 类模板作用:建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟类型来代表
//
// 语法:
// template<typename T> // typename可以写成 class,与typename没啥具体区别
// 类
//
// 类模板与函数模板区别:
// 1.类模板没有自动类型推导的使用方式,所以必须指定
// 2.类模板在模板参数列表中可以有默认参数
//
// 类模板中成员函数的创建时机
// 1.普通类中的成员函数一开始就可以创建
// 2.类模板中的成员函数在调用时才开始创建
//
// 类模板对象做函数参数
// 类模板实例化出对象,向参数传参
// 三种传参方式:
// 1.制定传入类型 直接显示对象的数据类型(最常用)
// 2.参数模板化 将对象中的参数变为模板进行传递
// 3.整个类模板化 将这个对象类型 模板化进行传递
//
// 类模板与继承
// 1.当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类T的类型
// 2.如果不指定,编译器无法给子类分配内存
// 3.如果想灵活制定出父类中T的类型,子类也需要变为模板
//
// 类模板的成员函数可以类外实现(类内声明,类外实现)
// 需要添加:1.作用域;2.参数模板/参数模板列表
//
// 类模板份文件编写
// 问题:类模板中成员函数创建时机是在 调用阶段 ,导致分文件编写时链接不到
//
// 解决:
// 方式1:直接包含.cpp源文件
// 方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp hpp是约定的名称,并不强制
//
// 类模板与友元
// 全局函数类内实现:直接在类内声明友元即可(建议使用类内实现)
// 全局函数类外实现:需要提前让解释器知道全局函数的存在
// 1.加一个空模板的参数列表<>
// 2.把代码剪切到代码文件的最上方,让编译器先看到
// 3.加入类的声明,提前让编译器看到模板类
//
C++进阶-1-模板基础(函数模板、类模板)的更多相关文章
- 3.2 STL中的函数对象类模板
*: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...
- C++—模板(2)类模板与其特化
我们以顺序表为例来说明,普通顺序表的定义如下: typedef int DataType; //typedef char DataType; class SeqList { private : Dat ...
- Python语法基础-函数,类以及调试处理
[TOC] 1. 函数的定义 python中函数有两种: python自带的函数 用户定义函数 返回多个值 原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同 ...
- C++ 模板的编译 以及 类模板内部的实例化
在C++中.编译器在看到模板的定义的时候.并不马上产生代码,仅仅有在看到用到模板时,比方调用了模板函数 或者 定义了类模板的 对象的时候.编译器才产生特定类型的代码. 一般而言,在调用函数的时候,仅仅 ...
- 类模板、Stack的类模板实现(自定义链栈方式,自定义数组方式)
一.类模板 类模板:将类定义中的数据类型参数化 类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合 (一).类模板的定义 template <类型形参表> clas ...
- 【02python基础-函数,类】
1.函数中的全局变量与局部变量全局变量:在函数和类定义之外声明的变量.作用域为定义的模块,从定义位置开始到模块结束.全局变量降低了函数的通用性和可读性,要尽量避免全局变量的使用.全局边个两一般作为常量 ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
- [Reprint] C++函数模板与类模板实例解析
这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...
- C++学习之函数模板与类模板
泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++ ...
随机推荐
- JDBC 中如何进行事务处理?
Connection 提供了事务处理的方法,通过调用 setAutoCommit(false)可以设置 手动提交事务:当事务完成后用 commit()显式提交事务:如果在事务处理过程中 发生异常则通过 ...
- docker-compose安装和使用
安装:https://my.oschina.net/thinwonton/blog/2985886 docker-compose和Dockerfile结合使用,创建django项目和postgres数 ...
- 简单描述 MySQL 中,索引,主键,唯一索引,联合索引 的区别,对数据库的性能有什么影响(从读写两方面) ?
索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们 包含着对数据表里所有记录的引用指针. 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的 ...
- java-属性集properties+加载配置文件
简介 /* 使用properties集合存储数据,遍历取出properties集合中的数据 properties集合有一些操作字符串的特有方法 Object setProperty(String ke ...
- 什么是 Spring MVC 框架的控制器?
控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现.控制器解 析用户输入并将其转换为一个由视图呈现给用户的模型.Spring 用一个非常抽象 的方式实现了一个控制层,允许用户创建多种用途的控 ...
- printf()函数压栈a++与++a的输出
printf()中a++与++a的输出问题 在C语言中有个很常用的函数printf(),使用时从右向左压栈,也就是说在printf("%d %d %d %d\n",a,a++,++ ...
- 从零开始开发一款H5小游戏(三) 攻守阵营,赋予粒子新的生命
本系列文章对应游戏代码已开源 Sinuous game. 每个游戏都会包含场景和角色.要实现一个游戏角色,就要清楚角色在场景中的位置,以及它的运动规律,并能通过数学表达式表现出来. 场景坐标 canv ...
- 小程序刷新webview小结
场景 在小程序其它页面做了操作,数据发生改变,回到webview页面时需要更新webview里面的数据.由于小程序没有提供与webview的实时通信能力,因此刷新页面是个可考虑的做法. 方法一 最常见 ...
- 子线程中如何修改ui界面
1.Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view包 ...
- java中的访问控制有什么用?如何用法?请举例
9.访问控制 [新手可忽略不影响继续学习] 访问控制有什么用?在软件公司里是这么用的,我们想像一种场景,在你的类中,你编了三个私有方法,马克-to-win,别人当然都用不了,但在类外,你也是用不了的, ...