IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++:泛型编程 -> 正文阅读

[C++知识库]C++:泛型编程

1.交换数字

通用写法

void mySwap(int &a,int &b)
{
    int temp = a;
    a =b;
    b= temp;
}
void test01()
{
    int a = 10;
    int b = 20;
    mySwap(a,b);
    cout<<a<<endl;
    cout<<b<<endl;
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
20
10

Process finished with exit code 0

泛型编程

1.自动类型推导,必须有参数类型才可以推导,不允许产生二义性。

//类型太多,逻辑相似
//类型参数化,泛型编程==模板技术
template <class T>   //告诉编译器,下面出现T,不要报错,T为通用类型
void mySwapT(T &a,T &b)
{
    T  temp = a;
    a =b;
    b= temp;
}
void test02()
{
    int a = 10;
    int b = 20;
    mySwapT(a,b);
    cout<<a<<endl;
    cout<<b<<endl;
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
20
10

Process finished with exit code 0

2.显示指定类型

  mySwapT<int>(a,b);

3.模板必须要指定T才可以运行
下面这段程序报错,T无法推导其类型

template <typename T>
void  mySwapT2()
{
    
}
void test03()
{
    mySwapT2<>();
}

2.利用模板实现通用数组排序

template <class T>
void SwapT(T &a,T &b)
{
    T  temp = a;
    a =b;
    b= temp;
}
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++)
        {
            if(arr[max] <arr[j])
            {
             max = j;
            }
        }
        if (max !=i)
        {
            //交换数据
            SwapT(arr[max],arr[i]);
        }
    }
}

//输出数组元素
template  <class T>
void printArray(T arr[],int len)
{
    for(int i= 0;i<len;i++)
        cout<<arr[i]<<" ";
    cout<<endl;
}

void test04()
{
    char arr[] = "helloworld";
    int n = sizeof(arr)/sizeof(char);
    mysort(arr,n);
    printArray(arr,n);
}

3.函数模板与普通函数的区别及调用规则

template 必须紧跟函数体

1.区别

template <class T>
T myPlus(T a, T b)
{
    return a+b;
}
int myPlus2(int a,int b )
{
    return a+b;
}
void test05()
{
    int a = 10;
    int b = 20;
    char c = 'c';  //a =97  c= 99
    myPlus(a,b);
    myPlus2(a,b);
//    cout<<myPlus(a,c)<<endl;  //错误 函数模板不可进行隐式类型转换
    cout<<myPlus2(a,c);        //普通函数可以进行隐式类型转换

}

2.普通函数和函数模板的调用规则

1.如果出现重载, 优先调用普通函数。
如果普通函数未实现,则报错

template <class T>
void myPrint(T a,T b)
{
    cout<<"template print"<<endl;
}
void myPrint(int a,int b)
{
    cout<<"common print"<<endl;
}

void test06()
{

    int a = 10;
    int b = 20;
    //如果出现重载, 优先使用普通函数。
        myPrint(a,b);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print

Process finished with exit code 0

2.如果强制调用模板函数,则使用空参数列表

    myPrint(a,b);
    myPrint<>(a,b);
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print

Process finished with exit code 0

3.函数模板可以实现重载

template <class T>
void myPrint(T a,T b)
{
    cout<<"template print"<<endl;
}
void myPrint(int a,int b)
{
    cout<<"common print"<<endl;
}
template <class T>
void myPrint(T a,T b,T c)
{
    cout<<"template reload print  "<<endl;
}

void test06()
{

    int a = 10;
    int b = 20;
    int c = 30;
    //如果出现重载, 优先使用普通函数。
    //如果普通函数未实现,则报错
    myPrint(a,b);
     //如果强制调用模板函数,则使用空参数列表
    myPrint<>(a,b);

    //模板函数重载
    myPrint(a,b,c);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print
template reload print

Process finished with exit code 0

4.如果函数模板可以产生更好的匹配,那么优先调用函数模板

void test06()
{

    int a = 10;
    int b = 20;
    int c = 30;
    //如果出现重载, 优先使用普通函数。
    //如果普通函数未实现,则报错
    myPrint(a,b);
     //如果强制调用模板函数,则使用空参数列表
    myPrint<>(a,b);

    //模板函数重载
    myPrint(a,b,c);

    char d = 'd';
    char e = 'e';
    myPrint(d,e);

}

调用函数模板不需要进行隐式类型转换

G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print
template reload print
template print

Process finished with exit code 0

4.模板机制

  • 编译器并不是把函数模板处理成能够处理任何类型的函数
  • 函数极板通过具体类型产生不同的函数
  • 编译器对模板函数进行两次编译,在声明的地方对模板本身进行编译,在调用的
    方对参数替换后的代码进行编译

5.模板的局限性及解决

通用模板有时无法完成函数体内的具体操作。

class Person
{
public: Person(string name,int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

private:
    string m_Name;
    int m_Age;
};
template <class T>
bool myCompare(T &a ,T&b)
{
 if(a > b)
     return true;
 else
     return false;
}
//通过具体化类型定义,解决上述问题

void test07()
{
    int a = 10;
    int b = 20;
    int ret = myCompare(a,b);
    cout<<ret<<endl;

    Person p1("tom",10);
    Person p2("jerry",20);
    int ret2 = myCompare(p1,p2);
    cout<<ret<<endl;
}

ret为0,ret2运行失败
解决方案:
通过具体化自定义数据类型,解决上述问题
调用这个函数时,程序会优先调用匹配度高的


template<> bool myCompare<Person>(Person &a,Person &b)
{
    if (a.m_Age>b.m_Age)
        return true;
    return false;

}

具体语法:template<>返回值 函数名 <具体类型>(参数)

6.类模板的基本使用

template <class NameType,class AgeType>
class Per
{
public:
    Per(NameType name,AgeType age)
    {
        this->m_name = name;
        this->m_age  = age;
    }
    void showPer()
    {
        cout<<this->m_name<<endl;
        cout<<this->m_age<<endl;
    }
      NameType  m_name ;
      AgeType  m_age;

};

void test08()
{
    //自动类型推导 类模板不支持
    //Per per("jerry",50);

    //显示指定类型
    Per<string,int>per("jay",40);
    per.showPer();
}

类模板可以有默认参数类型,函数模板不可以

template <class NameType,class AgeType = int>

7.函数的调用时机

class Person1
{
public:
    void showPerson1()
    {
        cout<<"Person1"<<endl;
    }
};

class Person2
{
public:
    void showPerson2()
    {
        cout<<"Person2"<<endl;
    }
};

template <class T>
class myClass
{
public:
    T obj;
    void func1()
    {
        obj.showPerson1();
    }
    void func2()
    {
        obj.showPerson2();
    }
};

void test09()
{
  myClass<Person1>m;
  m.func1();

}

成功调用

G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
Person1

Process finished with exit code 0

  m.func2();// 报错

成员函数 一开始不会创建出来,而是在运行时才去创建

8.类模板做函数的参数

template <class NameType,class AgeType = int>
class PersonNew
{
public:
    PersonNew(NameType name,AgeType age)
    {
        this->m_name = name;
        this->m_age  = age;
    }
    void showPer()
    {
        cout<<this->m_name<<endl;
        cout<<this->m_age<<endl;
    }
    NameType  m_name ;
    AgeType  m_age;

};



1.传入指定类型

void doWork(PersonNew<string,int>&p)
{
    p.showPer();
}
void test10()
{

PersonNew<string,int>personNew("mj",10);
doWork(personNew);

}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
mj
10

Process finished with exit code 0

2.参数模板化

template <class T1,class T2>
void doWork2(PersonNew<T1,T2>&p)
{
    p.showPer();
}
void test11()
{
    PersonNew<string,int>p1("lb",20);
    doWork2(p1);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
lb
20

Process finished with exit code 0

3.整体类型化

template <class T>
void doWork3(T &p)
{
    p.showPer();
}
void test12()
{
    PersonNew<string,int>p2("cj",20);
    doWork3(p2);
}

4.查看数据类型函数

//如何查看数据类型
template <class T1,class T2>
void doWork4(PersonNew<T1,T2>&p)
{
    cout<<typeid(T1).name()<<endl;
    p.showPer();
}
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 15:59:28  更:2021-07-15 16:00:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/20 14:40:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码