C++
一、函数提高
1、函数默认参数
- 在C++中,函数的形参列表中是可以有默认值的
- 语法:返回值类型 函数名 (参数=默认值){ }
int func(int a ,int b =20;int c = 30){
return a+b+c;
}
int main(){
//如果有自己传入的数据,就用自己的数据,如果没有,那么就用默认值
cout<<func(10)<endl;//60
cout<<func(10,30)<endl;//70
}
注意事项:
- 如果某个位置已经有了默认参数,那么从这个位置之后的都必须有默认值(以下为错误案例)
int func2(int a = 10,int b = 20, int c){
return a+b+c;
}
- 如果函数声明有默认参数,函数实现就不能有默认参数(以下为错误案例);声明和实现只能有一个有默认参数
int func(int a = 10,int b = 10);//函数声明
int func(int a = 20,int b = 20){
return a+b;//函数实现
}
int main(){
cout<<func(10,10)<<endl;//报错
return 0;
}
2、函数的占位参数
- C++中函数的参数列表可以有占位参数,用来做占位,调用函数时必须填补该位置
- 语法:返回值类型 函数名 (数据类型){ }
void func(int a, int){
cout<<"666"<<endl;
}
int main(){
func(10,10);//占位参数必须填补
return 0;
}
3、函数重载
(1)基本语法
- 作用:函数名可以相同,提高复用性
- 函数重载满足条件:(1)同一个作用域下(2)函数名称相同(3)函数参数类型不同,或者个数不同,或者顺序不同
- 注意:函数的返回值不可以作为函数重载的条件——
比如函数使用int和void
(2)注意事项
-
引用作为重载条件
-
函数重载碰到函数默认参数
为什么func(a)调用的是无const,因为int&a = a合法,而int& a = 10不合法,const int & a = 10合法;
二、模板
1、概念
- 建立通用的模具,大大提高复用性
2、函数模板
(1)作用
- 建立一个通用函数,其函数返回值类型和形参类型可以不具体定制,用一个虚拟的类型来代替
(2)语法
template<typename T>
函数声明或定义
解释:
代码演示
函数模板使用(如下)
使用模板的两种方式:自动类型推导,显示指定类型
总结
(3)注意事项
-
自动类型推导,必须推导出一致的数据类型T才可以使用
-
模板必须要确定出T 的数据类型,才可以使用
(4)案例–数组排序
#include <iostream>
using namespace std;
//排序:从大到小
//交换函数模板
template <class T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
//排序算法(选择排序)
template<class T>
void mySort(T arr[], int len) {
for (int i = 0; i < len; i++) {
int max = i;//认定最大值的下标
for (int j = i + 1; j < len; j++) {
//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值
if (arr[max] < arr[j]) {
max = j;//更新最大值的下标
}
}
if (max != i) {
//交换max和i下标的元素
mySwap(arr[max], arr[i]);
}
}
}
//提供打印数组的模板
template<class T>
void printArray(T arr[],int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test01() {
//测试char数组
char charArr[] = "badcfe";
int num = sizeof(charArr) / sizeof(char);
mySort(charArr, num);
printArray(charArr, num);
}
void test02() {
//测试int数组
int intArr[] = { 7,5,1,3,9,2,4,6,8 };
int num = sizeof(intArr) / sizeof(int);
mySort(intArr, num);
printArray(intArr, num);
}
int main() {
test01();
test02();
return 0;
}
3、普通函数和函数模板
(1)区别
- 普通函数调用的时候可以发生自动类型转换(称隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换
隐式类型转换就是比如以下在函数中将char类型隐式转换成int类型
总结:建议使用 显示指定类型的方式,去调用函数类型模板,因为可以自己确定通用类型T
(2)调用规则
1、规则
2、演示
总结:既然提供了函数模板,最好就不要提供普通函数,不然容易出现二义性
4、模板的局限性
因此c++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板
示例
总结:
5、类模板
(1)基本语法
-
作用:建立一个通用类,类中成员数据类型可以不具体制定,用一个虚拟的类型代表
-
语法:
template<typename T> 类
-
解释:
-
演示
-
总结:类模板和函数模板相似,在声明模板的时候template后面加类,此类称为类模板
(2)与函数模板的区别
1、区别
2、演示
(3)成员函数创建的时机
1、创建时机
2、演示
3、总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建
(4)类模板对象做函数参数
1、三种传入方式
2、演示
3、总结:最常用的是第一种
(5)类模板与继承
1、注意
2、演示
3、总结:如果父类是类模板,子类需要指定出父类中T的数据类型
(6)类模板成员函数类外实现
1、演示
2、总结:类模板中的成员函数类外实现时,需要加上模板参数列表
(7)类模板分文件编写
1、问题和解决方式
2、演示
(1)
(2)
3、总结:主流的解决方法是第二种,将类模板成员函数写到一起,并将后缀名改为 .hpp
(8)类模板与友元
演示:
总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别