C++进阶-1-模板基础(函数模板、类模板)

C++进阶-1-模板基础(函数模板、类模板)

C++进阶 模板

1.1 函数模板

  1 #include
  2 using namespace std;
  3
  4 // 模板
  5
  6 // 模板的简单实例
  7 // 要求:
  8 //        1.利用函数模板封装一个排序函数,可以对不同数据类型数组进行排序
  9 //        2.排序规则由大到小,排序算法为:选择排序
 10 //        3.分别利用char数组和int数组进行测试
 11
 12 // 交换函数模板
 13 template<class T>
 14 void mySwap(T& a, T& b) {
 15     T temp = a;
 16     a = b;
 17     b = temp;
 18 }
 19
 20 // 排序算法模板
 21 template<class T>  // 也可以写typename
 22 void mySort(T arr[], int len) {
 23     // 选择排序
 24     for (int i = 0; i < len; i++) {
 25         int max = i;  // 认定最大值下标
 26         for (int j = i + 1; j < len; j++) {
 27             // 认定的最大值 比 遍历出的最大值 要小,说明 j 下标的元素才是真正的最大值
 28             if (arr[max] < arr[j]) {
 29                 max = j;  // 更新最大值下标
 30             }
 31         }
 32         if (max != i) {
 33             // 交换下标为max和i的元素
 34             mySwap(arr[max], arr[i]);
 35         }
 36     }
 37 }
 38
 39 // 打印数字内容模板
 40 template<class T>
 41 void printArray(T arr[], int len) {
 42     for (int i = 0; i < len; i++) {
 43         cout << arr[i] << " ";
 44     }
 45     cout << endl;
 46 }
 47
 48
 49 void test01() {
 50
 51     // 测试数组 char类型
 52     char charArr[] = "badcfe";
 53     int num_charArray = sizeof(charArr) / sizeof(char);
 54     mySort(charArr, num_charArray);
 55     printArray(charArr, num_charArray);
 56
 57     // 测试数组 int类型
 58     int intArray[] = { 1, 3, 2, 6, 4, 5, 7 };
 59     int num_int = sizeof(intArray) / sizeof(int);
 60     mySort(intArray, num_int);
 61     printArray(intArray, num_int);
 62 }
 63
 64 int main() {
 65
 66     test01();
 67
 68     system("pause");
 69
 70     return 0;
 71 }
 72
 73 // 总结
 74 // C++除了面向对象编程思想外,还有 泛型编程 以及 STL 技术
 75 //
 76 // 模板:建立通用的模具,大大提高代码的复用性
 77 // 模板不可以直接使用,它只是一种框架
 78 // 模板的通用并不是万能的
 79 //
 80 // 模板分为:函数模板与类模板
 81 //
 82 //
 83 // 函数模板:
 84 //
 85 // 模板的作用:建立一个通用函数,其函数返回值类型和形参类型都可以不具体制定,用一个虚拟的类型来表示
 86 // 语法:
 87 //        template  // typename也可以写成 class
 88 //        函数生命或定义
 89 //    解释:T 通用的数据类型,名称可以替换,通常为大写字母
 90 //
 91 // 函数模板的使用方式有两种:自动类型推导、显示指定类型
 92 //
 93 // 模板注意事项:
 94 //        1.自动类型推导方式,必须推导出一致的数据类型T,才可以使用
 95 //        2.模板必须要确定出T的数据类型,才可以使用
 96 //
 97 // 普通函数与函数模板的区别
 98 //    1.普通函数调用可以发生自动类型转换(隐式转换);
 99 //    2.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
100 //    3.如果利用显示指定类型的方式,可以发生隐式转换;
101 //
102 //        所以,建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型
103 //
104 // 普通函数与函数模板的调用规则
105 //    1.如果函数模板和普通函数都有可以实现,编译器会优先调用普通函数
106 //    2.可以通过空模板参数列表来强制调用函数模板(加<>)
107 //    3.函数模板也可以发生重载
108 //    4.如果利用函数模板可以产生更好的匹配,优先调用函数模板
109 //
110 //        所以,既然提供了函数模板,就最好不要再提供普通函数了,否则出现二义性
111 //
112 // 模板的局限性
113 //    1.模板的通用型不是万能的
114 //        利用具体化的模板,可以解决自定义类型的通用化
115 //        学习模板不是为了写模板,而是在STL能够运用系统提供的模板
116 //
117  

1.2 类模板

#include
#include<string>
using namespace std;

// 类 模板

// 示例1
//template

// 类模板可以有默认参数
template<class Nametype, class Agetype = int>
class Person1 {
public:

    Person1(Nametype name, Agetype age) {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson() {
        cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
    }

    //string m_Name;
    //int m_Age;

    Nametype m_Name;
    Agetype m_Age;

};

void test01() {

    //Person p1("Tom", 19);  // 报错,无法自动推导类型
    //Person1 p1("Tom", 19);,>
    Person1<string> p1("Tom", 19);

    p1.showPerson();

}

// 示例2
// 类模板对象做函数参数,三种传入方式

template<class T1, class T2>
class Person2
{
public:
    Person2(T1 name, T2 age) {
        this->m_Name = name;
        this->m_Age = age;
    };

    void showPerson() {
        cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
    }

    T1 m_Name;
    T2 m_Age;

};

// 1.指定传入类型
void printPerson1(Person2<string, int>& p) {
    p.showPerson();
}

// 2.参数模板化
template<class T1, class T2>
void printPerson2(Person2& p) {
    p.showPerson();
    // 看一下编译器推导出的类型
    cout << "T1的类型为:" << typeid(T1).name() << endl;
    cout << "T2的类型为:" << typeid(T2).name() << endl;
}

// 3.整个类模板化
template<class T>
void printPerson3(T& p) {
    p.showPerson();
    cout << "T的类型为:" << typeid(T).name() << endl;
}

void test02() {
    Person2<string, int>p("小明", 20);

    // 1.指定传入类型(最常用)
    printPerson1(p);

    // 2.参数模板化
    printPerson2(p);

    // 3.整个类模板化
    printPerson3(p);
}

// 示例3 类模板与继承
template<class T>
class Base {
    T m;
};

// class Son:pubic Base  // 错误,C++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son1 :public Base<int> {  // 必须指定一个类型

};

// 如果想灵活制定出父类中T的类型,子类也需要变为模板
template<class T1, class T2>
class Son2 :public Base {
public:
    Son2() {
        cout << "T1的类型为:" << typeid(T1).name() << endl;
        cout << "T2的类型为:" << typeid(T2).name() << endl;
    }
    T1 obj;
};

void test03() {

    Son1 s1;

    Son2<int, char> s2;
}

// 示例4 类模板成员函数类外实现
template<class T1, class T2>
class Person4
{
public:
    Person4(T1 name, T2 age);  // 类内声明
    //{
    //    this->m_Name = name;
    //    this->m_Age = age;
    //};

    void showPerson();  // 类内声明
    //{
    //    cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
    //}

    T1 m_Name;
    T2 m_Age;

};

// 类外实现
template<class T1, class T2>
Person4::Person4(T1 name, T2 age) {
    this->m_Name = name;
    this->m_Age = age;
}

template<class T1, class T2>
void Person4::showPerson() {
    cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}

void test04() {
    Person4<string, int> p4("张三", 100);
    p4.showPerson();
}

int main() {

    // 类模板初识
    //test01();

    // 类模板对象做函数参数
    //test02();

    // 类模板与继承
    //test03();

    // 类模板成员函数类外实现
    test04();

    system("pause");

    return 0;
}

// 总结
//
// 模板分为:函数模板与类模板
//
//
// 类模板:
//
// 类模板作用:建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟类型来代表
//
// 语法:
//        template  // typename可以写成 class,与typename没啥具体区别
////
// 类模板与函数模板区别:
//    1.类模板没有自动类型推导的使用方式,所以必须指定
//    2.类模板在模板参数列表中可以有默认参数
//
// 类模板中成员函数的创建时机
//    1.普通类中的成员函数一开始就可以创建
//    2.类模板中的成员函数在调用时才开始创建
//
// 类模板对象做函数参数
//    类模板实例化出对象,向参数传参
//    三种传参方式:
//        1.制定传入类型    直接显示对象的数据类型(最常用)
//        2.参数模板化    将对象中的参数变为模板进行传递
//        3.整个类模板化    将这个对象类型 模板化进行传递
//
// 类模板与继承
//    1.当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类T的类型
//    2.如果不指定,编译器无法给子类分配内存
//    3.如果想灵活制定出父类中T的类型,子类也需要变为模板
//
// 类模板的成员函数可以类外实现(类内声明,类外实现)
//    需要添加:1.作用域;2.参数模板/参数模板列表
//
// 类模板份文件编写
//    问题:类模板中成员函数创建时机是在 调用阶段 ,导致分文件编写时链接不到
//
//    解决:
//        方式1:直接包含.cpp源文件
//        方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp hpp是约定的名称,并不强制
//
// 类模板与友元
//    全局函数类内实现:直接在类内声明友元即可(建议使用类内实现)
//    全局函数类外实现:需要提前让解释器知道全局函数的存在
//        1.加一个空模板的参数列表<>
//        2.把代码剪切到代码文件的最上方,让编译器先看到
//        3.加入类的声明,提前让编译器看到模板类
// ,>,>,>

Original: https://www.cnblogs.com/LYH-win/p/16225837.html
Author: Thomas_kaka
Title: C++进阶-1-模板基础(函数模板、类模板)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/567827/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球