第七章 C++函数模板介绍

以下是本人整理的C++基础知识点,内容并不包含全面的C++知识,只是对C++重点内容、特点进行整理和归纳。

7.1 C++函数模板介绍

泛型程序设计方法
    介绍:大量编写模板、使用模板的程序设计
    特点
        算法只实现一遍,适用于多种数据类型的处理
        减少重复代码的编写


模板分类
    函数模板和类模板

类型的参数化
    数据的类型通过参数来传递
    函数定义时,不指明具体的数据类型
    函数调用时,编译器根据传入的实参自动推断数据类型

函数模板
    函数模板介绍
        建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位)
        当发生函数调用时,再根据传入的实参来逆推出真正的类型

    函数模板语法
        写法1
            template <typename 类型参数1 , typename 类型参数2 , ...> 返回值类型  函数名(形参列表){...}

        写法2
            template <class 类型参数1 , class 类型参数2 , ...> 返回值类型  函数名(形参列表){...}
                class用于定义类型参数,和template用法一直


        例子
            template<typename T> void Swap(T *a, T *b){ T temp = *a; }
                template  关键字, 用于定义函数模板
                typename   关键字,用来声明具体的类型参数
                <typename T>  定义类型参数,也就是虚拟的类型,或者说是类型占位符
                template<typename T>  模板头



    函数模板和普通函数的区别
        普通函数:数据值的参数化
            所用到的数据,类型确定,但值不确定

        函数模板:数据类型和值的参数化
            所用到的数据,类型和值都不确定,编译器根据实参来确定值和类型



类模板
    介绍
        类模板将类中的数据的类型参数化
        可用于类的成员变量和成员函数

    类模板的语法
        类模板的声明
            template<typename 类型参数1 , typename 类型参数2 , …> class 类名
                {};

            template<class 类型参数1 , class 类型参数2 , …> class 类名
                {};


        类模板的使用
            实例化时,必须显式指明数据类型,编译器不会根据数据推演
            例子
                className<int, int>  obj(10, 20);
                className<int, float> obj(10, 15.5);
                className<float, char*> obj(12.4, "东经180度");

7.2 C++函数模板的重载

与常规的函数重载类似
用途:普通数据类型和数组类型的区分

7.3 C++函数模板的实参推断

模板实参推断
    通过函数实参来确定模板实参的过程叫模板实参推断

模板实参推断过程中的类型转换
    普通函数和模板函数的类型转换
        普通函数
            转换发生时机
                函数调用时

            转换过程分类
                算数转换
                    例如 int 转换为 float,char 转换为 int,double 转换为 int 等

                派生类向基类的转换
                    向上转型

                const 转换
                    将非 const 类型转换为 const 类型

                数组或函数指针转换
                用户自定类型的转换


        函数模板
            不显式指明模板实参时,仅能进行「const 转换」和「数组或函数指针转换」
            显式指明模板实参时,跟普通函数一样
            函数形参是引用类型时,数组不会转换为指针,类型参数仍然为数组类型


    为函数模板显式地指明实参
        func<int, int>(10, 10);
        特点
            从左到右的顺序与对应的模板参数匹配
            最右边的类型参数的实参可以省略(能够自动推断出来)
            显式地指明实参时,可以应用普通函数的类型转换

7.4 C++模板的显式具体化

函数模板可能无法处理某些数据类型
    函数模板中的运算符不一定适用于所有数据类型

函数模板的显式具体化
    语法
        template<> const STU&  Max<STU>(const STU& a, const STU& b);
        template<> const STU&  Max(const STU& a, const STU& b);
        特点
            <STU>是可选的,可去掉
            template<>  ,类型参数 已经被具体化,不需要



函数调用的调用顺序
    非模板函数 > 显示具体化模板  > 常规模板

类模板的显式具体化
    语法
        声明类模板
            template<class T1, class T2> class Point{...} //普通类模板
            template<> class Point<char*, char*>{...} //显式具体化模板
            template<typename T2> class Point<char*, T2>{...}  //部分显式具体化模板

        类外定义函数
            template<class T1, class T2> void Point<T1, T2>::fun(T1 x, T2 y){...} //普通类模板,需要带上模板头
            void Point<char*, char*>::fun(char* x, char*y){...} //显式具体化模板,不需要带上模板头

7.5 C++模板中的非类型参数

模板中除了包含类型参数,还可以包含非类型参数
例子
    template<typename T, int N> class Demo{ };
    template<class T, int N> void func(T (&arr)[N]);
    N 是一个非类型参数,用来传递数据的值,而不是类型

在函数模板中使用非类型参数
    template<typename T> void Swap(T a[], T b[], int len); //普通模板
    template<typename T, unsigned N> void Swap(T (&a)[N], T (&b)[N]);//含有非类型参数的模板

在类模板中使用非类型参数
    template<typename T, int N>  class Array{...}
    参数N是非类型参数

非类型参数的限制
    一个整数
        传递给它的实参必须是一个常量表达式

    一个指向对象或函数的指针(引用)
        绑定到该指针的实参必须存在于静态数据区,不能位于堆栈区

7.6 C++模板的实例化

模板和内存的关系
    模板不会占用内存,最终生成的函数或者类才会占用内存

模板的实例化
    由模板根据·实参类型生成特定的函数或类的过程
    通过类模板创建对象时,一般只需要实例化成员变量和构造函数
    模板函数只有被调用时才会被实例化

7.7 将C++模板应用于多文件编程

编译是针对单个源文件的
    只要有函数声明,编译器就能知道函数调用是否正确

链接时将函数(类)调用和函数(类)定义对应起来
    链接器的存在,函数声明和函数定义可以分开来

板的实例化是在编译期间,由编译器完成的
模板的声明和定义都应该放到同一个头文件中
    模板的实例化是由编译器完成的,而不是由链接器完成的,这可能会导致在链接期间找不到对应的实例
    编译器在实例化的过程中需要知道模板的所有细节

7.8 C++模板的显式实例化

隐式实例化和显式实例化
    隐式实例化
        在调用函数或者创建对象时由编译器自动完成

    显式实例化
        通过代码明确地告诉编译器需要针对哪个类型进行实例化
        好处是,可以将模板的声明和定义(实现)分散到不同的文件中


函数模板的显式实例化
    template<typename T> void Swap(T &a, T &b);//模板
    template void Swap(double &a, double &b);//显式实例化
    extern template void Swap(double &a, double &b);//显式实例化声明

类模板的显式实例化
    template<class T1, class T2> class Point{...}//模板
    template class Point<char*, char*>;//显式实例化
    extern template class Point<char*, char*>;//显式实例化声明

显式实例化的局限
    每次模板使用发生变化,都要增加新的显式实例化
    作为库时,开发者不知道使用者怎么调用
    注意:尽量少使用显式实例化,要将模板的声明和定义都放到头文件中

7.9 C++类模板与继承详解

类模板从类模板派生
    template <class T1, class T2> class A{...}
    template <class T1, class T2> class B : public A <T2, T1>{...}

类模板从模板类派生
    template<class T1, class T2> class A{... }
    template <class T>class B: public A <int, double>{...}

类模板从普通类派生
    class A{...}
    template<class T> class B: public A{...}

普通类从模板类派生
    template <class T> class A{...}
    class B: public A <int>{...}

7.10 C++类模板与友元详解

函数、类、类的成员函数作为类模板的友元
    template <class T>
        class Tmpl
        {
            friend void Func1();
            friend class A;
            friend void B::Func();

        };


函数模板作为类模板的友元
函数模板作为类的友元
类模板作为类模板的友元

7.11 C++类模板中的静态成员

类模板中可以定义静态成员
    从该类模板实例化得到的所有同类型的类都包含同样的静态成员
    该类模板定义之后,还需要在同一个文件内定义静态变量
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值