内容8 模版和string
typename T1,typename T2...是模板函数形参的数据类型要传入实参的数据类型几个不同的T就是代表函数模板可以接收几种不同数据类型的参数。一、类模板通用语法框架顶部模板格式templateclass T1, class T2, ..., class Tn class 类模板名 { // 类内成员定义 };template模板声明头和函数模板规则一致class T1/typename T1完全等价都用来声明类型占位符不能用structT1~Tn多个通用类型类里所有需要灵活类型的成员、函数都可以使用这些占位符类模板 通用“类图纸”实例化时指定具体类型编译器生成对应专属类代码。二、示例通用栈 Stack 类模板完整代码拆解1. 模板类定义#includeiostream using namespace std; // 单类型参数类模板 templatetypename T class Stack { public: // 构造函数默认容量4 Stack(size_t capacity 4) { _array new T[capacity]; // 动态开辟T类型数组 _capacity capacity; _size 0; } void Push(const T data); // 入栈函数声明 private: T* _array; // 存储任意类型数据的数组指针 size_t _capacity; // 栈总容量 size_t _size; // 当前元素个数 };关键点说明templatetypename TT是栈存储元素的通用类型可代表int/double/字符串/自定义类私有成员T* _array动态数组数组里每个元素都是类型T构造函数new T[capacity]根据传入的类型T开辟对应大小的数组Push(const T data)入栈接口接收任意T类型的常量引用避免拷贝。2. 类模板外部成员函数实现重点语法图片提示模板声明和定义不要拆分到.h和.cpp会链接报错templateclass T void StackT::Push(const T data) { // 扩容逻辑省略 _array[_size] data; _size; }语法强制规则函数上方必须重新写templateclass T类名后必须加TStackT::Push代表这是模板类StackT的成员函数参数依然使用通用类型const T data为什么不能分文件模板本身只是“图纸”编译时不会生成实体代码只有实例化如Stackint才会生成对应类代码。 若声明放.h、实现放.cpp编译器编译.cpp时看不到实例化代码不会生成函数实体最后链接找不到函数报未定义引用错误。规范写法类模板的声明实现全部写在同一个头文件.h中。3. Push函数逻辑_array[_size] data; // 将数据存入数组当前末尾位置 _size; // 当前元素数量1简单实现入栈操作扩容逻辑图片省略。4. main 函数类模板实例化使用int main() { Stackint st1; // 实例化T替换为int生成存储int的栈类 Stackdouble st2; // 实例化T替换为double生成存储double的栈类 return 0; }类模板必须显式指定类型类型和函数模板自动推导不同类模板无法靠参数自动推导T必须写int、doubleStackint st1编译器根据模板图纸把所有T替换成int生成一套全新的int栈代码Stackdouble st2同理生成double栈代码两个对象st1、st2属于完全不同的类类型互不干扰。三、函数模板 vs 类模板 核心区别总结对比项函数模板类模板实例化方式可自动类型推导调用时不用写必须手动指定类型无自动推导作用生成通用函数生成通用类容器、数据结构外部实现普通函数无额外类限定符函数前加模板头类名带T文件规范可分离声明定义声明实现必须同文件禁止拆分h/cpp四、补充易错点template只要写模板相关函数/类就必须写在最上方不能省略typename和class在模板参数列表中等价二选一类模板成员函数写在类外部时StackT::的T绝对不能漏不要把类模板实现放到.cpp会链接失败实例化类模板必须带尖括号指定类型不能直接写Stack st;。标准模板库STLstring类 用来管理字符串的类 本质是模板实例化出来的类string类的对象是字符顺序表或者是字符数组实现的可以动态增长typedef basic_stringchar string string类是被重命名的原生类型是类模板 basic_string12赋值构造字符串用“ ”34const char* s代表以\0空终止符结尾的 C 风格字符串的指针。直接写字符串就行7先不讲string拷贝构造析构string底层是动态开辟的数组会自己调用已讲完赋值重载string底层是字符顺序表字符数组所以重载[ ]有意义string重载了[ ]对象可以通过调用[ ]函数实现获取某位置字符修改对象中具体哪个字符。越界时可以快速检查。可以将该函数内联以减少调用代价在类内默认内联string S6(“hellow”);结果为