版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
大学计算机基础教学系列教材第四章C++模板和泛型编程2026年5月11日目录模板的概念第4.1节函数模板第4.2节类模板第4.3节010203CONTENTS模板特化第4.4节标准模板类第4.5节0405本章小结第4.6节062学习目标
掌握函数/类模板核心语法,包括定义、实例化及默认参数用法,能编写多类型通用代码。
理解模板参数传递机制,掌握类模板类外实现、继承及作为函数参数的3种传递方式。
熟悉模板特化/偏特化,能为特定类型定制模板实现,调整模板行为。精通vector/array特性与操作,明确其与传统数组差异及适用场景。建立泛型编程思维,能按需选择模板工具与容器,提升代码复用性。模板的概念013第4.1节4模板的概念C++允许在编译时定义函数和类的通用代码,使得函数或类可以用于多种数据类型,可将这些通用代码称为模板。通过模板,能够编写类型无关的代码,提高代码的重用性和灵活性。模板主要有两种类型:函数模板(FunctionTemplates):允许给出一个函数框架,在函数调用时根据参数的类型进行类型自动推导。类模板(ClassTemplates):允许定义一个通用类,在类模板实例化时根据类型参数自动生成具体的类。函数模板025第4.2节6函数模板的语法函数模板是为了编写与类型无关的通用函数,使得同一个函数可以接受不同类型的参数。主要由模板申明和定义实现两部分组成,其基本语法如下:template<typenameT>//或者template<classT>Tfunction_name(Tparam1,Tparam2){//函数实现}模板申明通常出现在函数或类的前面,用于告知编译器这是一个函数模板或类模板,模板参数将在实际使用时被指定或推导。模板申明由template关键字开始,后面跟着模板参数列表。模板参数列表通常是类型参数,也可以是非类型参数。函数模板的语法程序输出如下:template<typenameT>Tadd(Ta,Tb){ returna+b;}
intmain(){
intintResult=add(3,4);//T推导为int
doubledoubleResult=add(3.5,4.4);//T推导为double cout<<"Integerresult:"<<intResult<<endl;//输出:7 cout<<"Doubleresult:"<<doubleResult<<endl;//输出:7.9
return0;}Integerresult:7Doubleresult:7.97显式实例化显式实例化(用户指定):有时出于精度或性能等方面的考虑,希望明确指定模板参数类型,而不依赖推导。template<typenameT>Tabs(Tx){
returnx<0?-x:x;}
intmain(){ cout<<"abs<double>(10)="<<abs<double>(10)<<endl;
cout<<"abs<double>(-3.14)="<<abs<double>(-3.14)<<endl;
return0;}程序输出如下:abs<double>(10)=10abs<double>(-3.14)=3.148显式实例化:强制将整数10按照double类型处理显式实例化:对负浮点数进行处理隐式实例化隐式实例化:编译器根据实参的类型自动推导模板参数的具体类型。template<typenameT>Tabs(Tx){returnx<0?-x:x;}intmain(){
inta=-5;
doubleb=-3.14;cout<<abs(a)<<endl;//T被推导为intcout<<abs(b)<<endl;//T被推导为double
return0;}程序输出如下:53.14910引用传参和值传参模板函数与普通函数一样,也可以选择使用值传递或引用传递来处理参数,尤其引用传参允许在函数中直接修改调用者的实参。相对而言,值传参不会实现在函数体中直接修改调用者的实参。值传参,例如:下面的函数虽然语法上正确,但不会对原始变量a和b产生影响,因为仅交换了其副本。template<typenameT>voidswap1(Ta,Tb){Ttemp=a;a=b;b=temp;}引用传参和值传参引用传参,在swap2中,通过将参数申明为引用类型(T&)进行引用传参,能够真正实现参值的交换。template<typenameT>voidswap2(T&a,T&b){Ttemp=a;a=b;b=temp;}intmain(){intx=10,y=20;swap2(x,y);//调用模板函数进行交换
cout<<x<<","<<y<<endl;//输出:20,10
return0;}11默认模板参数template<typenameT=int>Tadd(Ta,Tb){
returna+b;}当调用模板函数时,如果没有指定类型参数,编译器将使用默认的类型。函数模板的默认模板参数语法如下:template<typenameT=int>:为模板类型参数T提供默认值int,如果调用时没有指定T的类型,编译器将使用int作为默认类型。12默认模板参数template<typenameT=int>Tadd(Ta,Tb){
returna+b;}intmain(){cout<<add(3,4)<<endl;//使用默认类型intcout<<add(3.5,4.5)<<endl;//T被推导为double
return0;}13程序输出如下:78类模板0314第4.3节15类模板的语法类模板的实现通常包括成员变量、成员函数、构造函数等。成员函数和成员变量的类型都可以是模板类型参数。类模板的语法结构如下:template<typenameT>classClassName{private:Tvar;public:ClassName(Tval):var(val){}TgetValue(){returnvar;}};template<typenameT>是申明模板,T是类型参数。classClassName是实现类模板,其中T将用于类的成员变量、成员函数等。16类模板的语法template<typenameT>classBox{private:Tprice;public:Box(Tp):price(p){}TgetValue(){returnprice;}};下面定义了一个类模板Box,用于创建可以存储任意类型数据的通用容器。类中包含一个私有成员变量price,通过构造函数初始化,并提供getValue()成员函数用于获取存储的值。17类模板的语法intmain(){Box<int>intBox(10);//创建一个存储整数的BoxBox<double>doubleBox(3.14);//创建一个存储浮点数的Boxcout<<"IntegerBox:"<<intBox.getValue()<<endl;//输出:10cout<<"DoubleBox:"<<doubleBox.getValue()<<endl;//输出:3.14return0;}程序输出如下:IntegerBox:10DoubleBox:3.14类模板作为函数参数在实际开发中,将类模板对象作为函数参数时,需根据泛化程度选择不同的参数定义方式,主要分为以下三类:指定类型,即固定模板参数template<classT1,classT2>classStu{public:Stu(T1num,T2name):num(num),name(name){}
voidshow(){cout<<"学号:"<<num<<",姓名:"<<name<<endl;}private:T1num;T2name;};18类模板作为函数参数voidprint(Stu<int,string>&stu){cout<<"[指定类型]";stu.show();}intmain(){Stu<int,string>s(1001,"张三");print(s);//可调用
return0;}程序输出如下:[指定类型]学号:1001,姓名:张三19类模板作为函数参数参数模板化,即函数模板接收任意组合该方式通过定义函数模板,将类模板的类型参数继续传递,使函数可适配任意类型组合的类模板对象。template<classT1,classT2>classStu{public:Stu(T1num,T2name):num(num),name(name){}
voidshow(){cout<<"学号:"<<num<<",姓名:"<<name<<endl;}private:T1num;T2name;};20类模板作为函数参数template<classT1,classT2>voidprint2(Stu<T1,T2>&stu){cout<<"[参数模板化]";stu.show();}intmain(){Stu<int,string>s1(1002,"李四");Stu<double,string>s2(2001.5,"王五");print2(s1);print2(s2);
return0;}程序输出如下:[参数模板化]学号:1002,姓名:李四[参数模板化]学号:2001.5,姓名:王五21类模板作为函数参数通用模板类型,即完全泛化最通用的方式是使用一个模板类型T接收任何具有show()方法的对象,不限于某个类模板。template<classT1,classT2>classStu{public:Stu(T1num,T2name):num(num),name(name){}
voidshow(){cout<<"学号:"<<num<<",姓名:"<<name<<endl;}private:T1num;T2name;};22类模板作为函数参数//接收任何类型的对象,只要其有show()方法即可template<classT>voidprint3(T&obj){cout<<"[通用类型]";obj.show();}intmain(){Stu<int,string>s(1003,"赵六");print3(s);
return0;}23程序输出如下:[通用类型]学号:1003,姓名:赵六成员函数的类外实现template<classT1,classT2>classStu{public:Stu(T1num,T2name);//构造函数申明
voidshow();//成员函数申明private:T1num;T2name;};template<classT1,classT2>Stu<T1,T2>::Stu(T1num,T2name){
this->num=num;当类模板中的成员函数定义较多或较复杂时,推荐将其放在类体外进行实现。为了正确解析模板参数,类外定义时必须显式标明模板类型。2425成员函数的类外实现this->name=name;}template<classT1,classT2>voidStu<T1,T2>::show(){cout<<"学号:"<<num<<",姓名:"<<name<<endl;}intmain(){Stu<int,string>s(1001,"张三");s.show();return0;}程序输出如下:学号:1001,姓名:张三26类模板与继承C++允许类模板继承普通类、类模板继承类模板,并且在继承关系中可以使用泛型参数。这使得类模板可以实现更加灵活的层次结构。类模板继承普通类当一个类模板继承一个普通基类时,派生类模板仍然可以使用模板参数,同时也可以访问基类的非模板成员。类模板与继承//普通基类classBase{protected:
intbaseValue;public:Base(intv):baseValue(v){}
voidshowBase(){cout<<"BaseValue:"<<baseValue<<endl;}};//类模板派生类template<typenameT>classDerived:publicBase{private:TderivedValue;27类模板与继承public:Derived(intbaseVal,TderivedVal):Base(baseVal),derivedValue(derivedVal){}
voidshowDerived(){showBase();cout<<"DerivedValue:"<<derivedValue<<endl;}};intmain(){Derived<double>obj(10,20.5);obj.showDerived();
return0;}程序输出如下:BaseValue:10DerivedValue:20.52829类模板与继承类模板继承另一个类模板
如果一个类模板继承另一个类模板,需要在派生类中显式指定模板参数。类模板与继承//基类模板template<typenameT>classBase{protected:TbaseValue;public:Base(Tv):baseValue(v){}
voidshowBase(){cout<<"BaseValue:"<<baseValue<<endl;}};//派生类模板template<typenameT,typenameU>classDerived:publicBase<T>{private:UderivedValue;30类模板与继承public:Derived(TbaseVal,UderivedVal):Base<T>(baseVal),derivedValue(derivedVal){}
voidshowDerived(){
this->showBase();cout<<"DerivedValue:"<<derivedValue<<endl;}};intmain(){Derived<int,double>obj(42,3.14);obj.showDerived();
return0;}程序输出如下:BaseValue:42DerivedValue:3.1431模板特化0432第4.4节完全特化模板特化分两种核心形式:①完全特化:为某一(组)特定类型提供完整实现,所有模板参数替换为具体类型,替代通用模板行为。②偏特化:为部分特定类型定制实现,通过部分匹配模板参数完成,无需确定所有参数类型。//原始模板定义template<typenameT>classClassName{//通用实现};//完全特化形式:所有模板参数都替换为具体类型template<>classClassName<SpecificType>{//为SpecificType提供的专属实现};33完全特化类模块的完全转化示例:template<typenameT>classBox{private:Tvalue;public:Box(Tval):value(val){}TgetValue(){returnvalue;}};//完全特化:为int类型提供特化版本template<>classBox<int>{private:
intvalue;34完全特化public:Box(intval):value(val){}
intgetValue(){returnvalue*2;}//特化版本:返回值为原值的两倍};//完全特化:为double类型提供特化版本template<>classBox<double>{private:
doublevalue;public:Box(doubleval):value(val){}
doublegetValue(){returnvalue/2;}//特化版本:返回值为原值的一半};35完全特化intmain(){Box<int>box1(10);//使用int类型的特化版本
Box<double>box2(3.14);//使用double类型的特化版本
Box<char>box3('A');//使用默认模板版本
cout<<"Box1(int):"<<box1.getValue()<<endl;cout<<"Box2(double):"<<box2.getValue()<<endl;cout<<"Box3(char):"<<box3.getValue()<<endl;return0;}程序输出如下:Box1(int):20Box2(double):1.57Box3(char):A36偏特化偏特化(部分特化):仅定制模板参数的一部分,用于优化或改变特定类型场景下的模板行为,常通过限制部分参数类型提供专属实现。//通用模板template<typenameT,typenameU>classBox{private:Tfirst;Usecond;public:Box(Tf,Us):first(f),second(s){}
voidprint(){cout<<"First:"<<first<<",Second:"<<second<<endl;}};37偏特化//偏特化:当两个模板参数是相同类型时template<typenameT>classBox<T,T>{private:Tfirst;Tsecond;public:Box(Tf,Ts):first(f),second(s){}
voidprint(){cout<<"Bothvaluesarethesametype:"<<first<<"and"<<second<<endl;}};intmain(){Box<int,double>box1(10,3.14);//使用通用模板38偏特化Box<int,int>box2(20,30);//使用偏特化版本
box1.print();//输出:First:10,Second:3.14box2.print();//输出:Bothvaluesarethesametype:20and30
return0;}39程序输出如下:First:10,Second:3.14Bothvaluesarethesametype:20and30偏特化偏特化不仅可以用于类模板,还可以用于函数模板。通过偏特化,可以更精细地控制模板的行为,尤其在模板参数组合较复杂时,能够提供更多的灵活性。如下代码所示,函数模板的偏特化,通过函数重载的方式对指针类型参数进行特殊处理。//通用模板template<typenameT>voidprint(Tvalue){cout<<"GeneralTemplate:"<<value<<endl;}//偏特化:当模板参数是指针类型时template<typenameT>voidprint(T*value){cout<<"PointerTemplate:"<<*value<<endl;}40偏特化偏特化的限制与注意事项:不支持仅依靠函数返回类型来区分模板的偏特化版本。如果需要为不同类型返回不同结果,可以通过特化类模板或特化成员函数来实现。偏特化需要考虑兼容性:偏特化后的代码必须能够与模板的通用部分兼容。否则,可能会导致编译器错误或不符合预期的行为。模板特化与重载的区别:模板特化是在模板本身的基础上做修改,而重载则是定义了多个函数(或类)的相同名称但不同参数类型。41标准模板类0542第4.5节43vectorvector是顺序容器,核心特性与价值如下:动态扩容:运行时按需调整数组容量,灵活适配不同规模数据存储。连续存储:采用连续内存空间,支持高效随机访问,使用方式类似普通数组。性能特点:对末尾元素的插入、删除操作效率高,是实现栈结构的优选。丰富功能:自带边界检查、迭代器遍历、容量控制等功能,适配各类动态数组需求场景。vectorvector是一个模板类,通过指定模板参数定义特定类型的向量。vector<T>V;//T:指定容器中元素的类型(如int、double、std::string等);//V:是vector容器对象的名称。通过以下代码可直观了解vector的4种核心初始化方式://默认构造一个空的vectorvector<int>v1;//使用数组初始化再通过指针范围构造vectorintarr[]={1,2,3,4,5};vector<int>v2(arr,arr+5);//构造函数会将[arr,arr+5)范围内的5个元素复制到v2中44vector//指定大小,并初始化所有元素为默认值(0)vector<int>v3(5);//生成[0,5)范围内的5个元素,其初始值都是0//指定大小,并初始化所有元素为指定值(10)vector<int>v4(5,10);//通过拷贝构造另一个vectorvector<int>v5(v2);//输出v2中所有元素(使用传统for循环)cout<<"v2contents:";for(inti=0;i<v2.size();++i){cout<<v2[i]<<"";}cout<<endl;//输出:v2contents:1234545vectorvector容器常用操作包括:添加和删除元素(如push_back、pop_back)、访问元素(使用[]或at)、容量管理(如size、resize、reserve)以及使用迭代器遍历元素(如begin、end)。添加与删除元素:常用的添加和删除操作包括push_back()、pop_back()、insert()和erase()。46push_back(value);//在末尾添加元素。pop_back();//移除末尾元素。insert(position,value);//在指定位置插入元素。erase(position);//删除指定位置的元素。vector以下代码通过具体示例演示这些操作的使用方式://使用传统方式初始化vectorintarr[]={1,2,3};vector<int>v(arr,arr+3);//添加元素v.push_back(4);//{1,2,3,4}v.insert(v.begin()+1,10);//{1,10,2,3,4}//删除元素v.pop_back();//{1,10,2,3}v.erase(v.begin());//{10,2,3}47vector访问元素,常用的访问元素操作包括at(index)、operator[]、front()和back()。at(index);//返回指定索引的元素,带边界检查。operator[];//返回指定索引的元素,不带边界检查。front();//返回第一个元素。back();//返回最后一个元素。以下代码通过具体示例演示这些操作的使用方式:intarr[]={10,20,30,40,50};vector<int>v(arr,arr+5);//构造vectorcout<<"Elementatindex2:"<<v.at(2)<<endl;//使用at()方法访问元素cout<<"Elementatindex3:"<<v[3]<<endl;//使用下标运算符[]cout<<"Firstelement:"<<v.front()<<endl;//获取第一个元素cout<<"Lastelement:"<<v.back()<<endl;//获取最后一个元素48vector容量管理,常用的操作包括size()、capacity()、resize(n)、reserve(n)和shrink_to_fit()。size();//返回当前元素的数量。capacity();//返回分配的存储容量。resize(n);//只有一个参数,表示“预留容量”resize(n,val);//修改元素数量并设定新增值reserve(n);//增加容量,避免频繁分配内存。shrink_to_fit();//减少容量,使其与实际元素数量一致。以下代码通过具体示例演示这些操作的使用方式://使用数组构造vectorintarr[]={1,2,3};vector<int>v(arr,arr+3);49vectorcout<<"Size:"<<v.size()<<endl;//输出:3cout<<"Capacity:"<<v.capacity()<<endl;//输出:初始容量,通常>=3//增加容量v.reserve(10);cout<<"NewCapacity:"<<v.capacity()<<endl;//输出:10//调整大小,增加两个值为100的元素v.resize(5,100);//传统for循环输出元素for(inti=0;i<v.size();++i){cout<<v[i]<<"";//输出:123100100}cout<<endl;50vector使用迭代器,vector支持迭代器,用于高效遍历和操作元素。常用的迭代器包括begin()和end()、rbegin()和rend()、cbegin()和cend()。begin();和end();//返回首迭代器和尾后迭代器。rbegin();和rend();//返回反向迭代器。cbegin();和cend();//返回常量迭代器。以下代码通过具体示例演示这些操作的使用方式:vector<int>v={10,20,30,40};//使用正向迭代器cout<<"Forwarditeration:";for(autoit=v.begin();it!=v.end();++it){cout<<*it<<"";//输出:10203040}cout<<endl;51vector//使用反向迭代器cout<<"Reverseiteration:";for(autoit=v.rbegin();it!=v.rend();++it){cout<<*it<<"";//输出:40302010}cout<<endl;//使用范围for循环cout<<"Range-basediteration:";for(autox:v){cout<<x<<"";//输出:10203040}cout<<endl;52vectorvector<vector<int>>matrix(3,vector<int>(3,0));//3x3矩阵,初始值为0for(inti=0;i<3;++i){for(intj=0;j<3;++j){matrix[i][j]=i+j;}}for(inti=0;i<matrix.size();++i){//输出矩阵:for(intj=0;j<matrix[i].size();++j){//[012]cout<<matrix[i][j]<<"";//[123]}//[234]cout<<endl;}53vector支持嵌套定义,可直接构建动态二维数组(如矩阵),无需预先固定大小,灵活适配数据需求。arrayarray是固定大小的数组类模板,需指定元素类型和编译期大小,比传统C数组更安全、功能多,支持初始化列表/构造赋值,兼顾类型安全与操作便捷性。array<T,N>arr;//T:指定数组中元素的类型(如int、double、string等);//N:数组的大小,必须是编译时常量;//arr:array容器对象的名称。54如下代码所示,array容器的基本用法包括定义、初始化和遍历操作。//定义一个大小为5的数组,元素类型为intarray<int,5>arr={1,2,3,4,5};//通过默认构造函数定义,所有元素初始化为0array<int,5>arr_default={};//{0,0,0,0,0}array//输出数组内容for(inti=0;i<arr.size();++i){cout<<arr[i]<<"";}cout<<endl;55array提供固定长度数组容器,既保留了普通数组的性能,又支持如迭代器等STL接口。程序输出如下:12345arrayarray容器常用操作包括:访问元素、填充与内容操作以及使用迭代器遍历元素。访问元素,常用访问元素的方法包括at(index)、operator[]、front()和back()。at(index);//返回指定位置的元素,进行边界检查。operator[];//返回指定位置的元素,但不进行边界检查。front();//返回第一个元素。back();//返回最后一个元素。以下代码通过具体示例演示这些操作的使用方式:array<int,5>arr={10,20,30,40,50};cout<<"Elementatindex2:"<<arr.at(2)<<endl;//使用at()进行边界检查cout<<"Elementatindex3:"<<arr[3]<<endl;//使用operator[]cout<<"Firstelement:"<<arr.front()<<endl;//获取第一个元素cout<<"Lastelement:"<<arr.back()<<endl;//获取最后一个元素56array数组大小与容量,常用方法包括size()、max_size()和empty()size();//返回数组的元素个数max_size();//返回数组可以容纳的最大元素个数(通常与size()相同)empty();//检查数组是否为空(即size()==0)。57以下代码通过具体示例演示这些操作的使用方式:array<int,5>arr={10,20,30,40,50};cout<<"Sizeofarray:"<<arr.size()<<endl;//输出:5cout<<"Isarrayempty?"<<(arr.empty()?"Yes":"No")<<endl;//输出:Nocout<<"Elementsusingrange-basedforloop:";for(intx:arr){cout<<x<<“”;//输出:1020304050}cout<<endl;array填充与排序,包括fill(value)、swap(other_array)、sort(arr.begin(),arr.end())。
fill(value);//用指定的值填充数组中的所有元素。swap(other_array);//交换两个数组的内容。sort(arr.begin(),arr.end())//对数组中的元素进行排序,默认按升序排列。以下代码通过具体示例演示这些操作的使用方式:array<int,5>arr={5,2,8,1,4};arr.fill(10)
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【苏教版】-小学一年级数学下册-第1课时 数数、数的组成
- 25年春【大象版】小学2年级科学上册【二上4单元《力和形变》教材编写思路与教学建议·杨春生】
- 铜陵市护士招聘笔试题及答案
- 铁岭市教师招聘考试题库及答案
- 2026春苏科版(新教材)小学信息技术四年级下册《保护好自己的数据》同步练习及答案
- 烹饪西点蛋糕裱花技巧题目及答案
- 设计师排版题库及答案
- 十堰市教师招聘笔试题及答案
- 深圳市专职消防员招聘面试题及答案
- 26年鼻咽癌精准医疗质控要点梳理
- 2025年中国冶金地质总局三局校园招聘48人笔试历年参考题库附带答案详解
- 2026年园林绿化高大树木修剪与高空作业车使用测试
- (2025年)电气工程概论课后思考题参考答案
- 2026中国电气装备储能科技有限公司社会招聘笔试历年参考题库附带答案详解
- JJF 1836-2020微量分光光度计校准规范
- GB/T 30341-2013机动车驾驶员培训教练场技术要求
- GB/T 1095-2003平键键槽的剖面尺寸
- 施工扬尘治理六个百分百检查表格
- 32课件 国家电网公司电力安全工作规程线路部分
- 护士压力情绪管理课件
- 桥梁隧道施工监理控制要点课件
评论
0/150
提交评论