• C++ 提高编程 黑马教程(05)


    1.模板

    (1)简介
    /*
     * C++提高编程
     * 本阶段主要针对C++泛型编程 和 STL技术 做详细讲解,探讨C++更深层的使用
     *
     * 1.模板
     * 概念:模板就是建立通用的模具,大大提高复用性
     *
     * 特点:
     *      模板不可以直接使用,它只是一个框架
     *      模板的通用并不是万能的
     */
    int main() {
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    (2)函数模板
    /*
     * 函数模板
     * 建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。
     * 语法:template
     *      函数声明或者定义
     *      解释:template--声明创建模板
     *          tempname --表明其后面的符号是一种数据类型,可用class替换
     *          T --通用的数据类型,名称可以替换,通常为大写字母
     *
     *  隐式模板 mySwap(a,b);
     *  显示模板 mySwap(a,b);
     *
     * 注意事项
     *      自动类型推导,需要推导出一致的数据类型T,才可以使用
     *      模板必须要确定出T的数据类型,才可以使用。
     */
    //函数模板
    template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型
    void mySwap(T &a,T &b){
        T temp=a;
        a=b;
        b=temp;
    }
    template<typename T>
    void func(){
        cout<<"fun 调用"<<endl;
    }
    void test01(){
        int a=10;
        int b=20;
        //1.自动类型推导
        mySwap(a,b);
        //2.显示指定类型
        mySwap<int>(a,b);
        cout<<"a="<<a<<endl;
        cout<<"b="<<b<<endl;
    }
    int main() {
        test01();
        func<int>();
        return 0;
    }
    
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    (3)函数模板案例
    /*
     * 函数模板案例
     *
     * 描述:
     *      利用函数模板封装一个排序的函数,可以对不同数据类型素组进行排序
     *      排序规则从大到小,排序算法为选择排序
     *      分别利用char数组和int数组进行测试
     *
     */
    
    template<class T>
    void mySort(T arr[],int len){
        for(int i=0;i<len;i++){
            int max=i; //认定最大值得小标
            for(int j=i+1;j<len;j++){
                //认定的最大值比遍历出的数组要小,说明j下表的数值大
                if(arr[max]<arr[j]){
                    max=j;
                }
            }
            if(max!=i){
                T temp=arr[max];
                arr[max]=arr[i];
                arr[i]=temp;
            }
        }
    }
    
    //冒泡排序
    template<typename T>
    void sayArray(T arr[],int len) {
        cout << "数组元素为:" << sizeof(arr) <<endl;
        for (int i = 0; i < len; i++) {
            cout << arr[i] << endl;
        }
    }
    
    void test01() {
        char charArr[]="abcdef";
        int num=sizeof (charArr)/ sizeof(char);
        mySort(charArr,num);
        sayArray(charArr,num);
    }
    
    int main() {
        test01();
        return 0;
    }
    
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    (4)普通模板和函数模板的调用规则
    /*
     * 普通函数和函数模板的调用规则
     *      如果函数模板和普通函数都可以实现,优先调用普通函数
     *      可以通过空模板参数列表来强制调用函数模板  myPrint<>(2,2);
     *      函数模板也可以发生重载
     *      如果函数模板可以产生更好的匹配,优先调用函数模板
     */
    
    void myPrint(int a, int b) {
        cout << "调用的普通函数" << endl;
    }
    
    template<typename T>
    void myPrint(T a, T b) {
        cout << "调用的模板" << endl;
    }
    
    //函数模板 重载
    template<typename T>
    void myPrint(T a, T b, int) {
        cout << "调用的模板" << endl;
    }
    
    int main() {
        myPrint(1, 2);
    
        //空模板参数列表,强制调用函模板
        myPrint<>(2, 2);
    
        //如果函数模板产生更好的匹配,优先调用函数模板
        myPrint('1', 'a');
        return 0;
    }
    
    
    • 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
    (5)模板的局限性
    /*
     * 模板的局限性
     * 模板的通用性并不是万能的
     * 有些特定数据类型,需要用具体化方式做特殊实现
     */
    
    class Person {
    public:
        string name;
        int age;
    
        Person(string name, int age) {
            this->name = name;
            this->age = age;
        }
    
        bool operator==(Person &p) {
            cout<<"operator== 函数被调用了"<<endl;
            if (this->name == p.name && this->age == p.age) {
                return true;
            } else {
                return false;
            }
        }
    };
    
    //对比两个数据是否相等
    template<class T>
    bool myCompare(T &a, T &b) {
        if (a == b) {
            return true;
        } else {
            return false;
        }
    }
    
    void test01() {
        int a = 20;
        int b = 20;
        bool ret = myCompare(a, b);
        if (ret) {
            cout << "a==b" << endl;
        } else {
            cout << "a!=b" << endl;
        }
    }
    
    void test02() {
        Person p1("张三", 10);
        Person p2("李四", 10);
        bool ret = myCompare(p1, p2);
        cout << "p1==p2:" << ret << endl;
    }
    
    int main() {
    
        test01();
    
        test02();
    
        return 0;
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    (7)类模板
    (1)类模板开胃菜
    /*
     * 类模板
     * 类模板语法:
     * 建立一个通用类,类中的成员 数据类型可以不具体定制,用一个虚拟的类型来代表。
     *
     * 语法:
     *      template
     *      类
     * 解释:
     *      template -- 声明创建模板
     *      typename -- 表明其后面的符号是一种数据类型,可以用class'代替
     *      T -- 通用的数据类型,名称可以替换,通常为大写字母
     *
     */
    
    //类模板
    template<class nameType, class ageType>
    class Person {
    public:
        nameType name;
        ageType age;
    
        Person(nameType name, ageType age) {
            this->name = name;
            this->age = age;
        }
    
        void showPerson() {
            cout << "name=" << this->name << ";age=" << age << endl;
        }
    };
    
    void test01() {
        Person<string, int> p1("孙大圣", 28);
        p1.showPerson();
        Person p2("孙大圣2", "282");
        p2.showPerson();
    }
    
    int main() {
        test01();
        return 0;
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    (2)类模板与函数模板的区别
    /*
     * 类模板和函数模板区别
     *      1.类模板没有自动类型推导的使用  自己使用的版本为C++20,以支持自动推导
     *      。类模板在模板参数列表中可以有默认参数
     *
     */
    
    //类模板与函数模板的区别
    template<class nameType, class ageType=string>
    class Person {
    public:
        nameType name;
        ageType age;
    
        Person(nameType name, ageType age) {
            this->name = name;
            this->age = age;
        }
    
        void showPerson() {
            cout << "name=" << this->name << ";age=" << age << endl;
        }
    };
    
    //1.类模板没有自动类型推导使用方式
    void test01() {
        Person p1("孙悟空", 1000);
    }
    
    //2.类模板在模板参数列表中可以有默认参数
    void test02() {
        Person p2("aaa", 123);
        p2.showPerson();
        Person p3("bbb", '234');
        p3.showPerson();
    }
    
    int main() {
        test02();
        return 0;
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    (3)类模板中成员函数创建时机
    /*
     * 类模板中成员函数创建时机
     *
     * 类模板中成员函数和普通类中成员函数创建时机是有区别的
     *      普通泪中的成员函数一开始就可以创建
     *      类模板中的成员函数在调用时候才创建
     *
     */
    
    class Person1 {
    public:
        void showPerson1() {
            cout << "Person1" << endl;
        }
    };
    
    class Person2 {
    public:
        void showPerson2() {
            cout << "Person2 show" << endl;
        }
    };
    
    template<class T>
    class myClass {
    public:
        T obj;
    
        //类模板中的成员函数
        void func1() {
            obj.showPerson1();
        }
    
        void func2() {
            obj.showPerson2();
        }
    };
    
    void test01() {
        myClass<Person1> m;
        m.func1();
        //m.func2(); //报错,提示没有这个方法
        myClass<Person2> m2;
        m2.func2();
    }
    
    int main() {
        test01();
        return 0;
    }
    
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    (4)类模板对象做函数参数
    *
     * 类模板对象做函数参数
     *
     * 学习目标:类模板实例化出的对象,向函数传参的方式
     *
     * 三种方式:
     *      1.指定传入的类型:直接显示对象的数据类型
     *      2.参数模板化:将对象中的参数变为模板进行传递
     *      3.整个类模板化:将这个对象类型 模板化进行传递
     *
     */
    
    template<class T1, class T2>
    class Person {
    public:
        T1 name;
        T2 age;
    
        Person(T1 name, T2 age) {
            this->name = name;
            this->age = age;
        }
    
        void showPerson() {
            cout << "name=" << name << ";age=" << age << endl;
        }
    };
    
    //1.指定传入类型
    void printPerson1(Person<string, int> &p) {
        p.showPerson();
    }
    
    void test01() {
        Person<string, int> p("孙悟空", 100);
        printPerson1(p);
    }
    
    template<class T1, class T2>
    void printPerson2(Person<T1, T2> &p) {
        p.showPerson();
        cout << "T1类型为:" << typeid(T1).name() << endl;
        cout << "T2类型为:" << typeid(T1).name() << endl;
    }
    
    //2.参数模板花
    void test02() {
        Person<string, int> p("猪八戒", 90);
        printPerson2(p);
    }
    
    template<class T>
    void printPerson3(T p) {
        p.showPerson();
    }
    
    //3.整个类模板化
    void test03() {
        Person<string, int> p("唐山", 20);
        printPerson3(p);
    }
    
    int main() {
        cout << "test01()" << endl;
        test01();
        cout << "test02()" << endl;
        test02();
        cout << "test03()" << endl;
        test03();
        return 0;
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    (5)类模板与继承
    /*
     * 类模板与继承
     *
     * 当类模板碰到继承时,需要注意:
     *      当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中的T的类型
     *      如果不指定,编译器无法给子类分配内存
     *      如果想灵活指定出父类中T的类型,子类也需要变为类模板
     *
     */
    
    //类模板与继承
    template<class T>
    class Base {
        T m;
    };
    
    //class Son:public Base{ //错误,必须要知道父类中的T类型,才能继承给子类
    //
    //};
    
    class Son : public Base<int> {
    
    };
    
    void test01() {
        Son son;
    }
    
    //如果想灵活指定父类中T类型,子类也需要变类模板
    template<class T1, class T2>
    class Son2 : public Base<T2> {
    public:
        T1 obj;
        Son2() {
            cout << "T1类型为:" << typeid(T1).name() << endl;
            cout << "T2类型为:" << typeid(T2).name() << endl;
        }
    };
    
    void test02() {
        Son2<int, char> s2;
    }
    
    int main() {
        test01();
        test02();
        return 0;
    }
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    (6)类模板成员函数类外实现
    /*
     * 类模板成员函数类外实现
     * 学习目标:能够掌握类模板中的成员函数类外实现
     */
    
    template<class T1,class T2>
    class Person{
    public:
        T1 name;
        T2 age;
        Person(T1 name,T2 age);
        void showPerson();
    };
    
    //类模板 成员函数类外实现
    template<class T1,class T2>
    Person<T1,T2>::Person(T1 name,T2 age){
        this->name=name;
        this->age=age;
    }
    //成员函数的类外实现
    template<class T1,class T2>
    void Person<T1,T2>::showPerson(){
        cout<<"姓名:"<<name<<";年龄="<<age<<endl;
    }
    
    
    
    void test01(){
        Person<string,int> p("AAA",18);
        p.showPerson();
        Person p2("AAA",18);
        p2.showPerson();
    }
    
    int main() {
        test01();
        return 0;
    }
    
    
    • 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
    • 38
    • 39
    • 40
    (7)类模板与友元
    /*
     * 类模板与友元
     *
     * 学习目标:
     *      掌握类模板配合友元函数的类内和类外实现
     *  全局函数类内实现 -- 直接在类内声明友元即可
     *  全局函数类外实现 -- 需要提前让编译器知道全局函数的存在
     */
    
    //让编译器提前知道Person类的存在
    template<class T1, class T2>
    class Person;
    
    //类外实现
    //加空模板参数列表
    //如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
    template<class T1, class T2>
    void printPerson2(Person<T1, T2> p) {
        cout << "类外实现:姓名:" << p.name << ";年龄:" << p.age << endl;
    }
    
    //通过全局函数打印Perosn信息
    template<class T1, class T2>
    class Person {
        //全局函数 类内实现
        friend void printPerson(Person<T1, T2> p) {
            cout << "姓名:" << p.name << ";年龄:" << p.age << endl;
        }
    
        //全局函数 类外实现
        friend void printPerson2();
    
    public:
        T1 name;
        T2 age;
    
        Person(T1 name, T2 age) {
            this->name = name;
            this->age = age;
        }
    };
    
    //1.全局函数类内实现
    void test01() {
        Person p1("Tom", 18);
        printPerson(p1);
    }
    
    //1.全局函数类外实现
    void test02() {
        Person p2("Dog", 22);
        printPerson(p2);
    }
    
    int main() {
        test01();
        test02();
        return 0;
    }
    
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    (8)类模板案例
    未学习
    https://www.bilibili.com/video/BV1et411b73Z?p=183
    
    • 1
    • 2
  • 相关阅读:
    Vue3.0——常用的Composition API(监听属性、Vue3生命周期、Teleport、自定义事件、状态驱动的动态 CSS、Suspense)
    会议OA之待开会议&所有会议
    Google测试之道读后感
    oracle数据库的导入与导出
    Java毕业设计选题推荐 SpringBoot毕设项目分享
    JAVA中的集合类型的理解及应用
    Java基础---第十一篇
    day2-web安全漏洞攻防-基础-弱口令、HTML注入(米斯特web渗透测试)
    使用TypeScript和jsdom库实现自动化数据抓取
    乔迁之喜!泛微软件园启用,欢迎新老朋友来坐坐
  • 原文地址:https://blog.csdn.net/minyeling/article/details/132639978