C++类和对象:构造/析构/拷贝函数
你好,这里是新人 Sunfor
这篇是我最近对于C++模板编程初阶的学习心得和错题整理
有任何错误欢迎指正,欢迎交流!
会持续更新,希望对你有所帮助,我们一起学习,一起进步
前言
C++模板是泛型编程的基石,它让代码具备“一写多用”的超能力
通过模板,我们可以编写与数据类型无关的通用代码,既能提升开发效率,又能确保类型安全,本文将带你深入模板的底层逻辑,并通过实战案例掌握其核心用法
一、模板核心概念
1.1 为什么需要模板?
在之前类和对象的学习内容中,我们了解到函数重载,这对比C语言的重命名已经方便不少,但是一些重载的函数,逻辑是十分类似的,我们反复写相似的代码也会浪费程序编写效率,这个时候就需要用到模板
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
//......
如果我们使用模板,便有以下几个优点
- 代码复用:一套代码适配多种类型
- 类型安全:编译期类型检查
- 性能无损:无运行时的开销
模板be like:
1.2 什么是泛型编程?
编写与 类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础
二、函数模板
2.1 函数模板的概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
2.2 函数模板的定义和使用
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
cout << Add(3, 4) << endl;
cout << Add(2.5, 3.6) << endl;
//不允许:类型不明确
//cout << Add(3, 4.4) << endl;
return 0;
}
typename 是用来定义模板的参数关键字,也可以使用 class
2.3 函数模板的工作原理
- 编译器实例化:编译器根据调用类型生成具体函数
- 隐式实例化:根据参数自动推导类型
- 显示实例化:手动指定模板参数
函数模板是一个蓝图,它本身不是函数,是编译器用使用方法产生特定具体类型函数的模具,其实模板就是把我们本身需要做的事情丢给了编译器去做
2.4 隐式实例化vs显示实例化
//隐式实例化
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 10.1, b2 = 20.2;
Add(a1, a2);
Add(b1, b2);
Add(a1, (int)b2);//强制类型转换成int
return 0;
}
//显式实例化
int main(void)
{
int a = 10;
double b = 20.2;
Add<int>(a, b);
return 0;
}
三、类模板
3.1 类模板的基础语法
template<class T>
class MyArray//模板名
{
//类内成员定义
public:
MyArray(int size) :_size(size)
{
_data = new T[size];
}
~MyArray()
{
delete[] _data;
}
T& operator[](int index)
{
return _data[index];
}
private:
T* _data;
int _size;
};
MyArray<int> intArr(10);
MyArray<string> strArr(5);
注意:模板不建议声明和定义分离到两个文件.h和.cpp 可能会出现链接错误
3.2 综合实战
//通用链表
template<typename T>
class LinkedList
{
private:
struct Node
{
T data;
Node* next;
//构造函数 初始化列表
Node(const T& val):data(val),next(nullptr){}
};
Node* _head;
public:
LinkedList():_head(nullptr){}
void PushFront(const T& val)
{
Node* newNode = new Node(val);
newNode->next = _head;
_head = newNode;
}
void PrintAll()const
{
Node* curr = _head;
while (curr)
{
cout << curr->data << "->";
curr = curr->next;
}
cout << "NULL" << endl;
}
~LinkedList()
{
while (_head)
{
Node* temp = _head;
_head = _head->next;
delete temp;
}
}
};
LinkedList<int> intList;
intList.PushFront(10);
intList.PushFront(20);
LinkedList<string> strList;
strList.PushFront("Hello");
strList.PushFront("World");
四、模板使用的注意事项
- 编译期特性
模板代码需要放在头文件中
模板错误通常在实例化时才会暴露- 类型限制
template<typename T> T Max(T a, T b) { return (a > b) ? a : b; // 要求T必须支持>操作符 }
- 命名约定
模板参数通常使用T, U, V等大写字母
复杂场景使用描述性名称:template<typename ElementType> class Container { /*...*/ };
后记
模板是C++赋予开发者的“代码模具”,它让泛型思维照进现实,从此类型不再是创意的枷锁。从简单的Swap函数到复杂的STL容器,模板的魅力在于:用更抽象的代码,表达更普适的逻辑。但这才只是起点——模板元编程、STL等进阶技术,将为你打开编译期计算的新维度。保持好奇心,下面我们将进入STL的学习,探索如何利用STLt提升效率,让你的C++技能更上一层楼~