C++提高编程部分总结

前言
这里是对于想要深入了解C++编程的同学的关于提高编程部分的总结,请在了解了核心部分和基础部分后再看本部分总结,不然有些地方很难懂
1 模板
1.1 模板概念
概念:建立通用的模具,大大提高复用性
特点:
- 模板不可以直接使用,它只是一个框架
- 模板的通用并不是万能的
运用思想:泛型编程
模板机制:
- 函数模板
- 类模板
作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。
语法:
1 | template<typename T> |
注意事项:
自动类型推导,必须推导出一致的数据类型T,才可以使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//利用模板提供通用的交换函数
template<typename T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void printArray(T arr[], int len) {
for (int i = 0; i < len; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void test()
{
//1、自动类型推导
int a=1;
char b='b';
//这样不同的类型就不能用模板来实现
mySwap(a, b);
printArray(charArr, num);
printArray(intArr, num);
}模板必须要确定出T的数据类型,才可以使用(但T为什么根据情况来,没有特殊要求可以任取)
1
2
3
4
5
6
7
8
9
10
11
12
13
14//利用模板提供通用的交换函数
template<typename T>
void func()
{
cout<<'hhh'<<endl;
}
void test()
{
//2、显示指定类型
func();//错误
func<int>();//正确
}
局限性:
- 模板的通用性并不是万能的
- 简单赋值操作不能用于数组
- 普通数据类型不能用于类数据类型
拓展性(局限性的解决):(用具体化的方式实现特殊情景)
具体化(
template<>
)其实也是另一种重载形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
template<> bool myCompare(Person &p1, Person &p2)
{
if ( p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)
{
return true;
}
else
{
return false;
}
}
1.2 函数模板
函数模板作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。
语法:
1 | template<typename T> |
1.2.1 函数模板使用方法
自动类型推导(IDE自己判断)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//利用模板提供通用的交换函数
template<typename T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test()
{
//1、自动类型推导
mySwap(a, b);
}显示指定类型(<类型>——自己传入类型)
1 | //利用模板提供通用的交换函数 |
1.2.2 普通函数与函数模板
一般不同时出现,除非故意这么写,或不小心多写了
区别:
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换
当传入为不同的类型参数时,模板函数不能推到,而普通函数可以(int与char,char会转为ascii码)
调用规则:
如果函数模板和普通函数都可以实现,优先调用普通函数
1
2
3
4
5
6
7
8
9
10
11//优先调用普通函数
void myPrint(int a, int b)
{
cout << "调用的普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
cout << "调用的模板" << endl;
}可以通过空模板参数列表来强制调用函数模板
1
2//空模板参数列表
myPrint<>(a, b); //调用函数模板函数模板也可以发生重载
1
2
3
4
5
6
7
8
9
10
11//函数模板重载
template<typename T>
void myPrint(T a, T b)
{
cout << "调用的模板" << endl;
}
template<typename T>
void myPrint(T a, T b, T c)
{
cout << "调用重载的模板" << endl;
}如果函数模板可以产生更好的匹配,优先调用函数模板
1
2
3
4//考虑更好的匹配机制,优先调用函数模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1, c2); //调用函数模板
1.3 类模板
类模板作用:
- 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
语法:
1 | template<class T> |
示例:
1 | //类模板 |
1.3.2 成员函数
1.3.2.1 创建时机
类模板中的成员函数在调用时才创建
1 | class Person1 |
1.3.2.2 类外实现
类模板中成员函数在类内声明,在类外实现定义
注意事项:类模板中成员函数类外实现时,需要加上模板参数列表
1 | //类模板中成员函数类外实现 |
1.3.3 类模板对象做函数参数
传入方式:
1 | //类模板 |
指定传入的类型 — 直接显示对象的数据类型
1
2
3
4
5
6
7
8
9
10//1、指定传入的类型
void printPerson1(Person<string, int> &p)
{
p.showPerson();
}
void test01()
{
Person <string, int >p("孙悟空", 100);
printPerson1(p);
}参数模板化 — 将对象中的参数变为模板进行传递
1
2
3
4
5
6
7
8
9
10
11
12
13
14//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
p.showPerson();
cout << "T1的类型为: " << typeid(T1).name() << endl;
cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{
Person <string, int >p("猪八戒", 90);
printPerson2(p);
}整个类模板化 — 将这个对象类型 模板化进行传递
1
2
3
4
5
6
7
8
9
10
11
12
13//3、整个类模板化
template<class T>
void printPerson3(T & p)
{
cout << "T的类型为: " << typeid(T).name() << endl;
p.showPerson();
}
void test03()
{
Person <string, int >p("唐僧", 30);
printPerson3(p);
}
1.3.4 模板中导出系统给模板定义的数据类型
关键词:typeid
语法:typeid(T).name()
1.3.5 类模板与继承
注意事项:
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
1
2
3
4
5
6
7
8
9
10template<class T>
class Base
{
T m;
};
//class Son:public Base //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son :public Base<int> //必须指定一个类型
{
};如果不指定,编译器无法给子类分配内存
如果想灵活指定出父类中T的类型,子类也需变为类模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << typeid(T1).name() << endl;
cout << typeid(T2).name() << endl;
}
};
void test02()
{
Son2<int, char> child1;
}
1.3.6 类模板与函数模板区别
类模板与函数模板区别主要有两点:
类模板没有自动类型推导的使用方式(需要自己在定义类对象的时候加上<>)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
Person p("孙悟空", 1000); // 错误 类模板使用时候,不可以用自动类型推导
Person <string ,int>p("孙悟空", 1000); //必须使用显示指定类型的方式,使用类模板类模板在模板参数列表中可以有默认参数
1
2
3template<class NameType, class AgeType = int>
Person <string> p("猪八戒", 999); //类模板中的模板参数列表 可以指定默认参数
1.3.7 类模板分文件编写
可用于类外实现的情况
方法:
- 直接包含.cpp源文件
- 将声明.h和实现.cpp写到同一个文件中,并更改后缀名为
.hpp
,.hpp
是约定的名称,并不是强制(主流)
提示:
- 在.h源文件中,
#pragma once
防止头文件重复包含
1.3.8 类模板与友元
实现方法:
全局函数类内实现 - 直接在类内声明友元即可(建议用此)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26template<class T1, class T2>
class Person
{
//1、全局函数配合友元 类内实现
friend void printPerson(Person<T1, T2> & p)
{
cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
void test01()
{
Person <string, int >p("Tom", 20);
printPerson(p);
}全局函数类外实现 - 需要提前让编译器知道全局函数的存在(将在类外实现的函数提前写,还要提前写明类与模板)
全局函数提前
1
2
3
4template<class T1,class T2>
printPerson2(Person<T1,T2>p){
cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}类模板提前
1
template<class T1, class T2>
类声明提前
1
class Person;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38template<class T1, class T2>
class Person;
//函数模板的实现
template<class T1,class T2>
printPerson2(Person<T1,T2>p){
cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}
//以上为提前告诉编译器的东西
template<class T1, class T2>
class Person
{
//2、全局函数配合友元 类外实现
//普通函数的声明
friend void printPerson2(Person<T1, T2> & p);
//函数模板的声明
friend void printPerson2<>(Person<T1, T2> & p);
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
void test02()
{
Person <string, int >p("Jerry", 30);
printPerson2(p);
}
具体提高部分引入
这里是黑马程序员的免费资料,本人从网盘中下载下来了,要学习完整C++基础资料的可以访问下面链接,链接为我的博客(搬运过来了),里面也有C++基础资料的网盘分享
C++提高编程- Title: C++提高编程部分总结
- Author: ZJ
- Created at : 2024-10-25 18:00:00
- Updated at : 2025-01-17 01:36:25
- Link: https://blog.overlordzj.cn/2024/10/25/C++/提高部分总结/
- License: This work is licensed under CC BY-NC-SA 4.0.