C++_模板

C++ 专栏收录该内容
8 篇文章 0 订阅

目录

知识点1【函数模板的概述】(了解)

1、函数模板概述

2、函数模板 会自动推导 参数的类型

3、函数模板 可以显示指定T的类型

4、函数模板 和 普通函数同名

5、提供具体化的模板

知识点2【类模板】(了解)

1、类模板的定义

2、类模板的成员函数 在类外实现

3、类模板作为函数的参数

4、类模板 派生 普通类

5、类模板 派生 类模板

6、类模板 头文件和源文件 分离问题(.hpp)

知识点3【类模板和友元】(了解)

1、普通函数 作为 类模板 的友元

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

知识点4【设计数组类模板】(了解)


知识点1【函数模板的概述】(了解)

模板的分类:函数模板、类模板。

函数返回值类型形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板

模板的关键字:template

template<typename T> 
void swapAll(T & a,T & b)
{
    T temp = a;
    a = b;
    b = temp;
}

int a = 10, b = 20;
swapAll(a, b);---->int替換T 进行二次编译

函数模板、类模板:(进行两次编译)

第一次编译:不在乎T具体是啥类型 对函数模板本身进行编译

第二次编译:在函数模板 调用处 分析T的类型,进行二次编译

1、函数模板概述

template<typename T>
void swapAll(T & a,T & b)
{
    T temp = a;
    a = b;
    b = temp;
}
void test01()
{
    int a = 10, b=20;
    cout<<"a="<<a<<", b="<<b<<endl;
    swapAll(a, b);
    cout<<"a="<<a<<", b="<<b<<endl;

    char a1 = 'A', b1='B';
    cout<<"a1="<<a1<<", b1="<<b1<<endl;
    swapAll(a1, b1);
    cout<<"a1="<<a1<<", b1="<<b1<<endl;
}

//a=10, b=20
//a=20, b=10
//a1=A, b1=B
//a1=B, b1=A

2、函数模板 会自动推导 参数的类型

3、函数模板 可以显示指定T的类型

template<typename T>
T myAdd(T a, T b)
{
    return a+b;
}
void test02()
{
    int a=10;
    char b = 'B';
    // 无法自动推导 a b类型不一致
    //cout<<myAdd(a,b)<<endl;
    //显示指定T的类型
    cout<<myAdd<int>(a,b)<<endl;
}

4、函数模板 普通函数同名

//函数模板
template<typename T>
T myAdd(T a, T b)
{
    cout<<"函数模板"<<endl;
    return a+b;
}

//普通函数
int myAdd(int a, int b)
{
     cout<<"普通函数"<<endl;
    return a+b;
}

void test02()
{
    int a = 10, b = 20;

    //函数模板和普通函数 都识别 优先选择 普通函数
    cout<<myAdd(a,b)<<endl;

    //函数模板和普通函数 都识别 强制调用函数模板
    cout<<myAdd<>(a,b)<<endl;
}

写两个函数模板联系一下吧:

1、写一个可以遍历任何类型数组(将数组内容通过标准输出打印出来)

2、写一个可以排序任何类型数组(从大到小的顺序排序)

#include <iostream>
#include <cstring>

using namespace std;

template <class T>
void printArray(T arr[], int len){
    for(int i=0; i<len; i++){
        cout<<arr[i]<<"";
    }
    cout<<endl;
}

template <class T>
void mysort(T arr[], int len){
    for(int i=0; i<len; i++){
        for(int j=len-1; j>i; j--){
            if(arr[j] > arr[j-1]){
                T temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

int main(int argv, char **argc){
    char tempchar[] = "helloworld";
    int charlen = strlen(tempchar);

    int tempInt[] = {7, 4, 2, 9, 8, 1};
    int intlen = sizeof(tempInt)/sizeof(tempInt[0]);

    printArray(tempchar, charlen);
    printArray(tempInt, intlen);

    mysort(tempchar, charlen);
    mysort(tempInt, intlen);

    printArray(tempchar, charlen);
    printArray(tempInt, intlen);

    return 0;
}

/*
helloworld
742981
wroolllhed
987421
*/

5、提供具体化的模板

#include<string>
class Person
{
public:
    int num;
    string name;
public:
    Person(){}
    Person(int num, string name)
    {
        this->num = num;
        this->name = name;
    }
};

template<typename T>
T getMaxData(T a, T b)
{
    return a>b?a:b;//err 当a b是自定义对象 无法执行>运算符
    //解决办法一:重载>运算
}
void test04()
{
    cout<<getMaxData(10,20)<<endl;
    cout<<getMaxData('A','B')<<endl;

    Person ob1(100,"lucy");
    Person ob2(100,"bob");
    Person ret = getMaxData(ob1, ob2);
    cout<<ret.num<<", "<<ret.name<<endl;

}

函数模板的具体化:

#include<string>
class Person
{
public:
    int num;
    string name;
public:
    Person(){}
    Person(int num, string name)
    {
        this->num = num;
        this->name = name;
    }

#if 1
    bool operator>(Person ob)
    {
        cout<<"运算符重载"<<endl;
        if(num > ob.num)
            return true;
        return false;
    }

#endif
};

template<typename T>
T getMaxData(T a, T b)
{
    return a>b?a:b;//err 当a b是自定义对象 无法执行>运算符
    //解决办法一:重载>运算
    //解决办法一:重载>运算
}

//模板的具体化
template<> Person getMaxData<Person>(Person a, Person b)
{
    cout<<"具体化"<<endl;
    if(a.num > b.num)
        return a;
    return b;

}

void test04()
{
    cout<<getMaxData(10,20)<<endl;
    cout<<getMaxData('A','B')<<endl;

    Person ob1(100,"lucy");
    Person ob2(200,"bob");
    Person ret = getMaxData(ob1, ob2);
    cout<<ret.num<<", "<<ret.name<<endl;

}

int main(int argc, char *argv[])
{
    test04();
    return 0;
}

知识点2【模板】(了解)

1、类模板的定义

函数模板 的T 可以自动类型推导

类模板 的T 不可以自动类型推导 必须人为指定。

template<class T>
class Data
{
public:
    T a;
    T b;
public:
    Data(T a, T b)
    {
        this->a = a;
        this->b = b;
    }
    void showData()
    {
        cout<<"a="<<a<<", b="<<b<<endl;
    }
};
void test05()
{
    //类模板 必须显示指定T的类型
    //Data ob(10,20);//err
    Data<int> ob1(10,20);
    Data<char> ob2('A','B');

    ob1.showData();
    ob2.showData();
}

2、类模板的成员函数 在类外实现

template<class T>
class Data
{
public:
    T a;
    T b;
public:
    Data(T a, T b);
    void showData();
};

template<class T>
Data<T>::Data(T a, T b)
{
    this->a = a;
    this->b = b;
}

template<class T>
void Data<T>::showData()
{
    cout<<"a="<<a<<", b="<<b<<endl;
}

void test05()
{
    //类模板 必须显示指定T的类型
    //Data ob(10,20);//err
    Data<int> ob1(10,20);
    Data<char> ob2('A','B');

    ob1.showData();
    ob2.showData();
}

3、类模板作为函数的参数

template<class T>
class Data
{
public:
    T a;
    T b;
public:
    Data(T a, T b);
    void showData();
};

template<class T>
Data<T>::Data(T a, T b)
{
    this->a = a;
    this->b = b;
}

template<class T>
void Data<T>::showData()
{
    cout<<"a="<<a<<", b="<<b<<endl;
}

//void printData(const Data<int> &ob)
void printData(Data<int> ob)
{
    cout<<"a="<<ob.a<<", b="<<ob.b<<endl;
}

void test05()
{
    Data<int> ob(10, 20);

    printData(ob);
}

4、类模板 派生 普通类

        基类:类模板

        子类:普通类

#include <iostream>

using namespace std;
//类模板
template<class T>
class Base
{
public:
    T a;
public:
    Base(){cout<<"Base无参构造"<<endl;}
    Base(T a)
    {
        cout<<"有参构造"<<endl;
        this->a = a;
    }
    ~Base()
    {
        cout<<"Base的析构函数"<<endl;
    }
};

//普通类
class Son:public Base<int>//继承类模板的时候,必须要确定基类的大小

{
public:
    int b;
public:
    Son()
    {
        cout<<"Son的无参构造"<<endl;
    }
    Son(int a, int b):Base<int>(a),b(b)
    {
        cout<<"Son的有参构造"<<endl;
    }
    ~Son()
    {
        cout<<"Son析构函数"<<endl;
    }
};

int main(int argc, char *argv[])
{
    Son ob(10, 20);
    cout<<"ob.a="<<ob.a<<", ob.b="<<ob.b<<endl;
    return 0;
}

5、类模板 派生 类模板

        基类:类模板

        子类:类模板

#include <iostream>

using namespace std;
//类模板
template<class T>
class Base
{
public:
    T a;
public:
    Base(){cout<<"Base无参构造"<<endl;}
    Base(T a)
    {
        cout<<"有参构造"<<endl;
        this->a = a;
    }
    ~Base()
    {
        cout<<"Base的析构函数"<<endl;
    }
};

//类模板
template<class T1, class T2>
class Son:public Base<T1>

{
public:
    T2 b;
public:
    Son()
    {
        cout<<"Son的无参构造"<<endl;
    }
    Son(T1 a, T2 b):Base<T1>(a),b(b)
    {
        cout<<"Son的有参构造"<<endl;
    }
    ~Son()
    {
        cout<<"Son析构函数"<<endl;
    }
};

int main(int argc, char *argv[])
{
    Son<int, char> ob(10, 'B');
   cout<<"ob.a="<<ob.a<<", ob.b="<<ob.b<<endl;
    return 0;
}

6、类模板 头文件和源文件 分离问题(.hpp)

        建议不分离

        类模板定义和类模板成员函数实现都在.hpp文件中

        data.hpp

#ifndef DATA_H
#define DATA_H
#include<iostream>
using namespace std;

template<class T>
class Data
{
public:
    T a;
public:
    Data();
    Data(T a);
    void setA(T a);
    T getA(void);
};



template<class T>
Data<T>::Data()
{
    cout<<"无参构造"<<endl;
}

template<class T>
Data<T>::Data(T a)
{
    this->a = a;
    cout<<"有参构造"<<endl;
}

template<class T>
void Data<T>::setA(T a)
{
    this->a = a;
    return;
}

template<class T>
T Data<T>::getA()
{
    return a;
}

#endif // DATA_H

        main.cpp

#include <iostream>
#include "data.hpp"
using namespace std;

int main(int argc, char *argv[])
{
    Data<int> ob;
    ob.setA(100);
    cout<<ob.getA()<<endl;
    return 0;
}

知识点3【类模板和友元】(了解)

1、普通函数 作为 类模板 的友元

//普通函数作为类模板的友元
void printData01(Data<int> ob)
{
    cout<<"a="<<ob.a<<endl;
}
template <class T>
class Data{
    friend void printdata01(Data<int> ob);
private:
    T a;
public:
    Data(){
        cout << "无参构造" << endl;
    }
};

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

//函数模板 作为 类模板的友元
template<typename T2>
void printData02(Data<T2> ob)
{
    cout<<"a="<<ob.a<<endl;
}
template <class T>
class Data{
    friend void printdata01(Data<int> ob);
    
    template<typename T2> friend void printData01(Data<T2> ob);
private:
    T a;
public:
    Data(){
        cout << "无参构造" << endl;
    }
};
#include <iostream>

using namespace std;

template<class T>
class Data
{
    friend void printData01(Data<int> ob);

    template<typename T2>friend void printData02(Data<T2> ob);

private:
    T a;
public:
    Data()
    {
        cout<<"无参构造"<<endl;
    }

    Data(T a)
    {
        this->a = a;
        cout<<"有参构造"<<endl;
    }
};

//普通函数作为类模板的友元
void printData01(Data<int> ob)
{
    cout<<"a="<<ob.a<<endl;
}

//函数模板 作为 类模板的友元
template<typename T2>
void printData02(Data<T2> ob)
{
    cout<<"a="<<ob.a<<endl;
}

int main(int argc, char *argv[])
{
    Data<int> ob(100);
    printData01(ob);

    Data<char> ob2('B');
    printData02(ob2);

    return 0;
}

知识点4【设计数组类模板】(了解)

myarray.hpp

#ifndef MYARRAY_HPP
#define MYARRAY_HPP
#include<iostream>
#include<cstring>
using namespace std;
template<class T>
class MyArray
{
private:
    T *addr;
    int capacity;
    int size;
public:
    MyArray()
    {
        capacity=5;
        size = 0;
        addr = new T[capacity];
        memset(addr, 0, capacity*sizeof(T));
        cout<<"无参构造"<<endl;
    }
    MyArray(int capacity)
    {
        this->capacity = capacity;
        size = 0;
        addr = new T[capacity];
        memset(addr, 0, capacity*sizeof(T));
        cout<<"有参构造"<<endl;
    }
    MyArray(const MyArray &ob)
    {
        capacity = ob.capacity;
        size = ob.size;
        addr = new T[capacity];
        memcpy(addr, ob.addr, sizeof(T)*capacity);
        cout<<"拷贝构造函数"<<endl;
    }
    ~MyArray()
    {
        cout<<"析构函数"<<endl;
        if(addr != NULL )
        {
            delete [] addr;
            addr=NULL;
        }
    }

    int getSize(void)
    {
        return size;
    }
    int getCapacity(void)
    {
        return capacity;
    }

    //往数组尾部插入
    void push_back(T value)
    {
        //判断数组是否满
        if(size == capacity)
        {
            cout<<"数组已满,无法插入"<<endl;
            return;
        }
        else
        {
            addr[size] = value;
            size++;
        }
        return;
    }

    //尾部删除
    void pop_back(void)
    {
        if(size == 0)
        {
            cout<<"数组为空,无法删除"<<endl;
            return;
        }
        else
        {
            addr[size-1]=0;
            size--;
        }
        return;
    }

    //重载[]运算符
    T& operator[](int pos)
    {
        if(pos>=0 && pos<size)
        {
            return addr[pos];
        }
        else
        {
            cout<<"数组下标非法"<<endl;
        }
    }

};

#endif // MYARRAY_HPP

main.cpp

#include <iostream>
#include "myarray.hpp"
#include<string>
using namespace std;

class Hero
{
    friend ostream& operator<<(ostream &out, Hero ob);
private:
    string name;
    int def;
    int atk;
public:
    Hero(){}
    Hero(string name, int def, int atk)
    {
        this->name = name;
        this->def = def;
        this->atk = atk;
    }
};
ostream& operator<<(ostream &out, Hero ob)
{
    out<<ob.name<<" "<<ob.def<<" "<<ob.atk<<endl;
    return out;
}

int main(int argc, char *argv[])
{
    MyArray<int> arr1;
    arr1.push_back(10);
    arr1.push_back(20);
    arr1.push_back(30);
    arr1.push_back(40);

    int i=0;
    for(i=0;i<arr1.getSize(); i++)
    {
        cout<<arr1[i]<<" ";
    }
    cout<<endl;

    arr1[2]=3000;
    for(i=0;i<arr1.getSize(); i++)
    {
        cout<<arr1[i]<<" ";
    }
    cout<<endl;


    MyArray<char> arr2;
    arr2.push_back('A');
    arr2.push_back('B');
    arr2.push_back('C');
    arr2.push_back('D');
    for(i=0;i<arr2.getSize(); i++)
    {
        cout<<arr2[i]<<" ";
    }
    cout<<endl;

    MyArray<Hero> arr3;
    arr3.push_back(Hero("德玛西亚", 70, 100));
    arr3.push_back(Hero("小炮", 90, 80));
    arr3.push_back(Hero("艾希", 60, 70));
    arr3.push_back(Hero("小法", 70, 100));

    for(i=0;i<arr3.getSize(); i++)
    {
        cout<<arr3[i]<<" ";
    }
    cout<<endl;

    return 0;
}

  • 4
    点赞
  • 10
    评论
  • 15
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值