首页 > 其他分享 >18_模板

18_模板

时间:2023-10-11 17:16:01浏览次数:27  
标签:arr capacity 18 void template Data 模板

模板

c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。

凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。c++提供两种模板机制:函数模板和类模1板类属-类型参数化,又称参数模板

函数模板

函数模板的定义

模板关键字template

#include <iostream>

using namespace std;

//T只能对当前函数有效, typename可以换成class
template<typename T> void swapAll(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

int main()
{
    int a = 10, b = 20;
    //函数调用时, 更具实参类型 会自动推导T的类型
    swapAll(a, b);
    cout << a << " " << b << endl;
    
    char a1 = 'a', b1 = 'b';
    swapAll(a1, b1);
    cout << a1 << " " << b1 << endl;
    
    return 0;
}

函数模板 会编译两次:

1对函数模板自身编译

2函数调用处 将T的类型具体化

函数模板目标: 模板是为了实现泛型, 可以减轻编译的工作量, 增强函数的重用性

函数模板的注意点

函数模板和普通函数都识别(优先选择普通函数)

template<class T> void swapAll(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
    cout << "函数模板" << endl;
}

void swapAll(int &a, int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
    cout << "普通函数" << endl;
}

void main()
{
    int a = 10, b = 20;
    swapAll(a, b); //调用普通函数
}

函数模板 和 普通函数 都识别. 但强制使用函数模板

int main()
{
    int a = 10, b = 20;
    //强制使用函数模板
    swapAll<>(a, b); //调用函数模板
}

函数模板 自动类型推导 不能对函数的参数进行 自动类型转换

template<class T> void myPrintAll(T a, T b)
{
    cout << a << " " << b << endl;
    cout << "函数模板" << endl;
}

void myPrintAll(int a, int b)
{
    cout << a << " " << b << endl;
    cout << "普通函数" << endl;
}

int main()
{
    myPrintAll(10, 20); //普通函数
    myPrintAll('a', 'b'); //函数模板
    myPrintAll(10, 'b'); //普通函数 可以 自动类型转换
    //强制说明T为int类型 就支持自动类型转换
    myPrintAll<int>(10, 'b');
}

函数模板的重载

template<class T> void myPrintAll(T a)
{
    cout << a << endl;
    cout << "函数模板" << endl;
}

template<class T> void myPrintAll(T a, T b)
{
    cout << a << " " << b << endl;
    cout << "函数模板" << endl;
}

函数模板的局限性

当函数模板 推导出T为数组或其他自定义类型数据 可能导致运算符 不识别

解决方法

运算符重载(推荐)
#include <iostream>

using namespace std;

class Data
{
    friend ostream& operator<<(ostream& out, Data ob);
private:
    int data;
public:
    Data(){}
    Data(int data)
    {
        this->data = data;
    }
};

ostream& operator<<(ostream& out, Data ob)
{
    out << ob.data;
    return out;
}

template<class T> void myPrintAll(T a)
{
    cout << a << endl;
    cout << "函数模板" << endl;
}

int main()
{
    myPrintAll(10); //10
    myPrintAll('a'); //'a'
    Data ob1(100);
    myPrintAll(ob1); //100
}
具体化函数模板
#include <iostream>

using namespace std;

template<class T> void myPrintAll(T a)
{
    cout << a << endl;
    cout << "函数模板" << endl;
}

class Data
{
    friend void myPrintAll<Data>(Data ob);
private:
    int data;
public:
    Data(){}
    Data(int data)
    {
        this->data = data;
    }
};

//函数模板具体化
template<> void myPrintAll<Data>(Data ob)
{
    cout << ob.data << endl;
    cout << "函数模板具体化" << endl;
}

int main()
{
    myPrintAll(10);
    myPrintAll('a');
    Data ob(10);
    myPrintAll(ob);
    return 0;
}

类模板

类模板基本概念

有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。类模板用于实现类所需数据的类型参数化。

类模板的定义方式

#include <iostream>

using namespace std;

//类模板
template<class T1, class T2> class Data
{
private:
    T1 a;
    T2 b;
public:
    Data(){}
    Data(T1 a, T2 b)
    {
        this->a = a;
        this->b = b;
    }
    void showData()
    {
        cout << a << " " << b << endl;
    }
};

int main()
{
//    Data ob; //error 无参推导不出T的类型
    Data ob(10, 'c');
    Data<int, int> ob2(100, 'c');
    ob.showData();
    ob2.showData();
    return 0;
}

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

#include <iostream>

using namespace std;

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

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

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

int main()
{
    Data ob(100, 200);
    ob.showData();
    return 0;
}

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

#include <iostream>

using namespace std;

//类模板
template<class T1, class T2>
class Data
{
    template<class T3, class T4>
    friend void myPrintData(Data<T3, T4> &ob);
private:
    T1 a;
    T2 b;
public:
    Data(){}
    Data(T1 a, T2 b);
    void showData();
};

//函数模板
template<class T3, class T4>
void myPrintData(Data<T3, T4> &ob)
{
    cout << ob.a << " " << ob.b << endl;
}

int main()
{
    Data<int, char> ob(100, 'a');
    myPrintData(ob);
    return 0;
}

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

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

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

template<class T1, class T2>
class Data
{
    friend void myPrintData(Data<int, char> &ob);
private:
    T1 a;
    T2 b;
public:
    Data(){}
    Data(T1 a, T2 b);
    void showData();
};

void myPrintData(Data<int, char> &ob)
{
    cout << ob.a << " " << ob.b << endl;
}
int main()
{
   	Data<int, char> ob1(100, 'A');
    myPrintData(ob1);
}

模板头文件和源文件分离问题

模板. h文件 和 .cpp文件分离后main.cpp要都include才能运行,比较麻烦, 所以用.hpp包含这两部分

data.hpp

#ifndef DATA_H
#define DATA_H

#include<iostream>
using namespace std;

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

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

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

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

#endif // DATA_H

main.cpp

#include <iostream>
#include"data.hpp"

using namespace std;

int main()
{
    Data ob(100, 2);
    ob.showData();
    return 0;
}

案例: 设计数组类模板

myarray.hpp

#ifndef MYARRAY_HPP
#define MYARRAY_HPP
#include<iostream>
#include<string.h>

using namespace std;

template<class T>
class MyArray
{
    template<class T1>
    friend ostream& operator<<(ostream& out, MyArray<T1>& ob);
private:
    T *arr;
    int size;
    int capacity;
public:
    MyArray();
    MyArray(int capacity);
    MyArray(const MyArray &ob);
    ~MyArray();
    MyArray& operator=(MyArray &ob);
    void pushBack(T element);
    void sortArray();
};

template<class T>
MyArray<T>::MyArray()
{
    capacity = 5;
    size = 0;
    arr = new T[capacity];
    memset(arr, 0, sizeof(T)*capacity);
}

template<class T>
MyArray<T>::MyArray(int capacity)
{
    this->capacity = capacity;
    size = 0;
    arr = new T[capacity];
    memset(arr, 0, sizeof(T)*capacity);
}

template<class T>
MyArray<T>::MyArray(const MyArray &ob)
{
    if(arr != NULL)
    {
        delete[] arr;
        arr = NULL;
    }
    size = ob.size;
    capacity = ob.capacity;
    arr = new T[capacity];
    memset(arr, 0, sizeof(T)*capacity);
    memcpy(arr, ob.arr, sizeof(T)*capacity);
}

template<class T>
MyArray<T>::~MyArray()
{
    if(arr != NULL)
    {
        delete[] arr;
        arr = NULL;
    }
}

template<class T>
MyArray<T>& MyArray<T>::operator=(MyArray &ob)
{
    if(arr != NULL)
    {
        delete[] arr;
        arr = NULL;
    }
    size = ob.size;
    capacity = ob.capacity;
    arr = new T[capacity];
    memset(arr, 0, sizeof(T)*capacity);
    memcpy(arr, ob.arr, sizeof(T)*capacity);
    return *this;
}

template<class T>
void MyArray<T>::pushBack(T element)
{
    if(size == capacity)
    {
        capacity = capacity*2;
        T *tmp = new T[capacity];
        memset(tmp, 0, sizeof(T)*capacity);
        if(arr != NULL)
        {
            memcpy(tmp, arr, sizeof(T)*capacity);
            delete[] arr;
        }
        arr = tmp;
    }
    arr[size] = element;
    size++;
}

template<class T>
void MyArray<T>::sortArray()
{
    if(size == 0)
    {
        cout << "容器没有数据" << endl;
    }
    else
    {
        for(int i=0;i<size-1;i++)
        {
            for(int j=i+1;j<size;j++)
            {
                if(arr[i] > arr[j])
                {
                    T tmp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = tmp;
                }
            }
        }
    }
}

template<class T1>
ostream &operator<<(ostream &out, MyArray<T1> &ob)
{
    for(int i=0;i<ob.size;i++)
    {
        out << ob.arr[i] << " ";
    }
    return out;
}

#endif // MYARRAY_HPP

main.cpp

#include <iostream>
#include"myarray.hpp"
#include<string>

using namespace std;

class Person
{
    friend ostream& operator<<(ostream& out, Person& ob);
private:
    int num;
    string name;
    float score;
public:
    Person(){}
    Person(int num, string name, float score)
    {
        this->num = num;
        this->name = name;
        this->score = score;
    }
    bool operator>(Person& ob)
    {
        return num>ob.num;
    }
};

ostream& operator<<(ostream& out, Person& ob)
{
    out << ob.num << " " << ob.name << " " << ob.score;
    return out;
}

int main()
{
    MyArray<int> arr1;
    arr1.pushBack(20);
    arr1.pushBack(9);
    arr1.pushBack(80);
    arr1.pushBack(55);
    arr1.pushBack(79);
    arr1.pushBack(86);
    arr1.pushBack(15);
    arr1.pushBack(85);
    arr1.pushBack(100);
    arr1.pushBack(2);
    cout << arr1 << endl;
    arr1.sortArray();
    cout << arr1 << endl;

    MyArray<Person> arr2;
    arr2.pushBack(Person(3, "lucy", 98));
    arr2.pushBack(Person(1, "back", 45));
    arr2.pushBack(Person(7, "jack", 38));
    arr2.pushBack(Person(5, "wuh", 99));
    arr2.pushBack(Person(9, "lip", 85));
    arr2.sortArray();
    cout << arr2 << endl;
    return 0;
}

类模板的继承

类模板 派生出 普通类

#include <iostream>

using namespace std;

template<class T1, class T2>
class Base
{
private:
    T1 a;
    T2 b;
public:
    Base(){}
    Base(T1 a, T2 b);
    void showData();
};

template<class T1, class T2>
Base<T1, T2>::Base(T1 a, T2 b)
{
    this->a = a;
    this->b = b;
}

template<class T1, class T2>
void Base<T1, T2>::showData()
{
    cout << a << " " << b << endl;
}

//类模板派生出类模板
template<class T1, class T2, class T3>
class Son1: public Base<T1, T2>
{
public:
    T3 c;
public:
    Son1(T1 a, T2 b, T3 c): Base<T1, T2>(a, b){
        this->c = c;
    }
};

int main()
{
    Son1<int, char, int> ob1(100, 'A', 200);
    ob1.showData();
    cout << ob1.c << endl;
    return 0;
}

标签:arr,capacity,18,void,template,Data,模板
From: https://www.cnblogs.com/mzx233/p/17757645.html

相关文章

  • 八点五省联考 2018
    一双木棋状态数不多,直接爆搜https://loj.ac/s/1676274IIIDX考虑依次给\(i=1,2,\cdots,n\)填上数,每次尽量填最大的。考虑什么时候\(i\)填上\(x\)是合法的。考虑Hall定理,发现左部点约束最严的时候肯定是找一个已经填过的点\(u\),然后对所有\(d_v\ged_u\)的\(v\),选出......
  • 国标GB28181安防视频系统LiteGBS配置完成之后,视频无法播放是什么原因?
    国标GB28181系统LiteGBS设计了转码、上传一体化的功能,使音视频资源转码后可立即面向互联网进行发布和分发。在视频能力上,LiteGBS可以实现视频监控直播、录像检索与回看、云台控制、语音对讲、告警上报、平台级联等能力,在安防领域也有着广泛的应用,如明厨亮灶、平安乡村、雪亮工程、......
  • 问题记录贴:vue-i18n在弹出框中$t()报错:TypeError: Cannot read property '_t' of unde
    网上有用的解决方法:vue国际化在弹出框中$t()报错:TypeError:Cannotreadproperty'_t'ofundefined大佬给出的解决方法:弹窗是一个新的Vue对象,只需要单独给弹窗重新绑定i18n即可。代码://dialog/main.jsimportcustomDialogfrom'./dialog.vue'importi18nfrom'@/i18n'......
  • CodeForces 1882E2 Two Permutations (Hard Version)
    洛谷传送门CF传送门如何评价,模拟赛搬了一道,前一天晚上代码写了一半的题。考虑如何让操作次数最小。发现直接做太困难了。根本原因是,一次操作对序列的影响太大了。考虑做一些转化,减少一次操作对序列的影响。仍然先考虑一个排列怎么做。不知道为什么可以想到在排列前面添加特......
  • C++ - 模板
     本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层的使用1模板1.1模板的概念模板就是建立通用的模具,大大提高复用性 模板的特点:模板不可以直接使用,它只是一个框架模板的通用并不是万能的 1.2函数模板 C++另一种编程思想称为==泛型编程......
  • 计算几何模板--zhengjun
    二维structvec{ intx,y; vec(inta=0,intb=0):x(a),y(b){}};vecoperator+(constvec&a,constvec&b){ returnvec(a.x+b.x,a.y+b.y);}vecoperator-(constvec&a,constvec&b){ returnvec(a.x-b.x,a.y-b.y);}vecoperator*(constvec......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-18-处理鼠标拖拽-上篇
    1.简介本文主要介绍两个在测试过程中可能会用到的功能:在selenium中宏哥介绍了Actions类中的拖拽操作和Actions类中的划取字段操作。例如:需要在一堆log字符中随机划取一段文字,然后右键选择摘取功能。playwright同样可以实现元素的拖拽和释放的操作。2.拖拽操作鼠标拖拽操作,顾名......
  • Python模板字符串Template如:${变量名称}
    1.概述如果你在操作字符串,如果你操作的字符串内容很多,希望字符串中的内容能够根据规则动态替换,并且在长篇幅的字符串中需要替换任意位置任意次数的字符,使用str提供的replace方法代码会写的非常复杂,且出错不易排查。在这个场景中试试Template类把,他能够创建一个模板替换字符串。......
  • [CF1870F] Lazy Numbers
    LazyNumbers我觉得本题难度在于银剑的构造......我们把k进制下的数去掉前导零放在Trie树上,并且越高位的深度越小,这样我们看出某个节点的dfs序就是排名,称排名减数值为va。我们需要求va=0的点数。不难发现某一深度从左往右的va单调不降,所以可以二分求出每层的点......
  • CF 1877 C
    C.Joyboard这道题需要进行分类讨论。当\(k=1\)时,即构造的数组中所有元素皆为\(0\)才成立,所以输出\(1\)。当\(k=2\)时,只有\(a[n+1]<=n\)或\(a[n+1]=x\)(其中\(n|x\))才成立,所以答案是\(n+\lfloor\frac{n+m}{n}\rfloor\)\((m>n)\)。当\(k=3\)时,只有\(a[n+1]>n\)且\(a[n+......