返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++泛型编程综合讲解
  • 668
分享到

C++泛型编程综合讲解

C++泛型编程C++泛型 2022-12-26 15:12:29 668人浏览 薄情痞子
摘要

目录函数模板类模板函数符(Function)包装器函数模板 进一步把函数中的或类中的数据类型进一步抽象,这个抽象的类型就叫泛型 模板:函数模板,类模板 模板就是把函数(或类)中的类型

函数模板

进一步把函数中的或类中的数据类型进一步抽象,这个抽象的类型就叫泛型

模板:函数模板,类模板

模板就是把函数(或类)中的类型抽象出来,有指定类型方可使用

模板可以有默认类型,类模板规则(函数模板,不存在规则):从右到左

模板编译机制:

  • 编译器并不是把函数(类)模板处理成能够处理任何类型的函数(类),而是一个函数(类)的生成器。
  • 函数(类)模板通过具体类型产生不同的函数实例(类实体)。
  • 编译器会对函数(类)模板进行两次编译,第一次在声明的地方对模板本身进行编译(主要是对语法进行检查,在调用的地方对参数替换),再次对代码进行编译,二次编译也被称之为延时编译。

注意:模板函数需要编译两次,是慢于定义函数的原因

关键字template是模板标识符

<>是泛型,指定的参数类型列表

class用来修饰泛型,typename也可进行修饰

#include <iOStream>
using namespace std;
//int add(int a,int b){
//    return a+b;
//}
//float add(float a,float b){
//    return a+b;
//}
//string add(string a,string b){
//    return a+b;
//}
//抽象的泛型
template<class T>
T add(T a,T b){
    cout << "i am is template" << endl;
    return a+b;
}
int main()
{
    int a=10,b=20;
    cout << add(a,b) << endl;
    float a1=5.21;
    float b1=13.14;
    cout << add(a1,b1) << endl;
    string a2="yao",b2="liang";
    cout << add(a2,b2) << endl;//隐式调用
    cout << add<string>(a2,b2) << endl;//显示调用
    return 0;
}

显示调用和隐式调用

#include <iostream>
using namespace std;
//抽象的泛型
typename<class T>
T add(T a,T b){
    return a+b;
}
int main()
{
    string a2="yao",b2="liang";
    cout << add(a2,b2) << endl;//隐式调用
    cout << add<string>(a2,b2) << endl;//显示调用
    return 0;
}

函数模板的特化

前提:模板的特化(泛型没有制定类型)是依赖基础模板的

产生原因:当函数的算法逻辑与实际的参数类型不匹配时,就应该对类型进行特化

#include <iostream>
using namespace std;
template  <class T>
T compair(T t1,T t2){
    return t1>t2?t1:t2;
}
//对基础模板进行全特化(函数模板只能全特化,不能偏特化)
template <>
const char* compair(const char* str1,const char* str2){
    return string(str1)>string(str2)?str1:str2;
}
int main()
{
    int a=10,b=20;
    cout << compair(a,b) << endl;
    const char* str1="yaoliang";
    const char* str2="yao";
    cout << compair(str1,str2) << endl;
    return 0;
}

类型可以传*号

#include <iostream>
using namespace std;
template  <class T>
T compair(T t1,T t2){//char *t1=name; 
    cout << string(t1) << endl;
}
int main()
{
    char *name="minmin";
    char *name1="sun";
    compair(name,name1);
//    int a=10;
//    int *p=&a;
//    int *q=&a;
//    compair(p,q);
    return 0;
}

函数模板的调用优先级

函数实例>匹配的特化模板>基础模板

#include <iostream>
using namespace std;
template  <class T>
T compair(T t1,T t2){
    cout << "i am is basics" <<endl;
    return t1>t2?t1:t2;
}
//对基础模板进行全特化(函数模板只能全特化,不能偏特化)
template <>
const char* compair(const char* str1,const char* str2){
    cout << "i am is specialization" <<endl;
    return string(str1)>string(str2)?str1:str2;
}
inline int compair(int a,int b){
    cout << "i am is inline fun" << endl;
    return a>b?a:b;
}
int main()
{
    int a=10,b=20;
    cout << compair(a,b) << endl;
    const char* str1="yaoliang";
    const char* str2="yao";
    //如果是隐式调用,优先调用与之类型相匹配的特化模板
    cout << compair(str1,str2) << endl;
    //显性调用,直接调用
    cout << compair<const char*>(str1,str2) << endl;
    cout << compair<int>(a,b) << endl;
    return 0;
}

函数模板的实参推演

函数模板具有函数特性:函数重载

#include <iostream>
using namespace std;
template  <class T>
T add(T t1,T t2){
    cout << "i am is one_basics" <<endl;
    return t1+t2;
}
template  <class T1,class T2>
T1 add(T1 t1,T2 t2){
    cout << "i am is two_basics" <<endl;
    return t1+t2;
}
int main()
{
    int a=10,b=20;
    cout << add(a,b) << endl;
    double c=13.14;
    cout << add(c,a) << endl;
    return 0;
}

函数泛型不仅是一个单一抽象类型,也可以是一个组合类型。

#include <iostream>
#include <typeinfo>//信息识别头
using namespace std;
template <class T>
void my_funtion(T t){
    cout << "i am is basics" << endl;
    cout << typeid (t).name() << endl;
}
template <>
void my_funtion(int* t){
    cout << "指针类型的特化" << endl;
    cout << typeid (t).name() << endl;
}
template <class Ret,class Arg1,class Arg2>
void my_funtion(Ret (*arg)(Arg1,Arg2)){
    cout << typeid (Ret).name() << endl;
    cout << typeid (Arg1).name() << endl;
    cout << typeid (Arg2).name() << endl;
    cout << "指针类型的复合模板" << endl;
}
int add(int a,int b){
    return  a+b;
}
int main()
{
    int a=10;
    my_funtion(a);
    int *p=&a;
    my_funtion(p);
    my_funtion(add);
    return 0;
}

c++11关于函数模板的可变参符号…

…如果修饰类型(变量),则表示类型(变量)不定引数,个数不同,类型不同的多个参数。

#include <iostream>
using namespace std;
//函数实例
void print(){
};
template <class FirstArg,class... Args>
void print(FirstArg firstArg,Args... args){//int firstArg=100,...(3.14,"yaoliang")
    									//3.14 ...("yaoliang")
    									//"yaoliang" ...()
    cout << firstArg << " ";
    print(args...);
}
int main()
{
   print(100,3.14,"yaoliang");
   return 0;
}

类模板

像声明一个类一样声明一个模板,无隐式调用,模板规则:使用默认泛型参数类型,从右向左依次指定

#include <iostream>
using namespace std;
template <class T1,class T2>
class Person{
private:
    T1 _name;
    T2 _age;
public:
    Person(T1 name,T2 age){
        this->_age=age;
        this->_name=name;
    }
    int getAge(){
        return this->_age;
    }
    string getName(){
        return  this->_name;
    }
    virtual void showInfo(){
        cout << "姓名:" << this->_name << ",年龄:" << this->_age << endl;
    }
};
template <class T1,class T2,class T3=int>
class Stu:public Person<T1,T2>
{
private:
    const T3 _id;
    static int count;
public:
    Stu(T1 name,T2 age,T3 id):Person<T1,T2>(name,age),_id(id){
        count++;
    }
    void showInfo()override{
        cout << "学号:" << this->_id << ",姓名:" << this->getName() << ",年龄:" << this->getAge() << endl;
    }
    static int get_count(){
        return count;
    }
};
template <class T1,class T2,class T3>
int Stu<T1,T2,T3>::count=0;
int main()
{
    Person<string,int> *person=new Stu<string,int,int>("yao",19,1);
    person->showInfo();
    delete person;
    Stu<string,int> stu("sunsun",18,2);//使用缺省类型,从右往左
    stu.showInfo();
    cout << Stu<string,int,int>::get_count() << endl;
    return 0;
}

分文件编程实现一个顺序栈

注意: .hpp是类模板文件,声明和定义在同一个文件中

stack_cpp.hpp:

#ifndef MY_STACK_HPP
#define MY_STACK_HPP    
#include <exception>
#include <stdexcept>
#include <iostream>
using namespace std;
template <class T>
class my_stack{
private:
    T* m_data;
    int capacity;
    int size;
public:
    my_stack(int c=10);
    ~my_stack();
    bool full();
    bool empty();
    void push(const T& val);
    void pop();
    T& top();
};
#endif // MY_STACK_HPP
template<class T>
my_stack<T>::my_stack(int c)
{
    this->capacity=c;
    this->m_data=new T[capacity];
    this->size=0;
}
template<class T>
my_stack<T>::~my_stack()
{
    if(nullptr!=this->m_data){
        delete [] this->m_data;
        this->m_data=nullptr;
    }
    capacity=size=0;
}
template<class T>
bool my_stack<T>::full()
{
    return size==capacity;
}
template<class T>
bool my_stack<T>::empty()
{
    return size==0;
}
template<class T>
void my_stack<T>::push(const T &val)
{
    if(full()){
        return;
    }
    m_data[size]=val;
    size++;
}
template<class T>
void my_stack<T>::pop()
{
    if(this->empty()){
        throw range_error("空了");
    }
    size--;
}
template<class T>
T &my_stack<T>::top()
{
    return m_data[size-1];
}

main.cpp:

#include <iostream>
#include "my_stack.hpp"
using namespace std;
int main()
{
    my_stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    while (!s.empty()) {
        cout << s.top() << endl;
        s.pop();
    }
    return 0;
}

内嵌类

为外围类服务,不影响外围类

#include <iostream>
#include <vector>
using namespace std;
template <class T>
class A{
public:
    int a;
    class B{
    public:
        int b=10;
    };
};
int main()
{
    cout << sizeof (A<int>) << endl;//4
    A<int>::B b_obj;
    cout << b_obj.b << endl;
    cout << "------------vetor容器---------------" << endl;
    vector<int> v;
    for(int i=0;i<10;i++){
        v.push_back(rand()%100+1);
    }
    vector<int>::iterator it;
    for(it=v.begin();it!=v.end();it++){
        cout << *it << "   ";
    }
    cout << endl;
    return 0;
}

注意: 外围类和内围类之间不能相互访问,特殊的:静态属性

类模板的特化

#include <iostream>
using namespace std;
template <class T>
class A{
public:
    A(){
        cout << " A basics" << endl;
    }
};
template <>
class A<int>
{
public:
    A(){
        cout << " A 全特化 " << endl;
    }
};
template <class T>
class A<T*>
{
public:
    A(){
        cout << " A 偏特化" << endl;
    }
};
template <>
class A<int*>
{
public:
    A(){
        cout << " A 的全特化" << endl;
    }
};
template <class Ret,class Arg1,class Arg2>
class A<Ret (*)(Arg1,Arg2)>{
public:
    A(){
        cout << " A 的偏特化" << endl;
    }
};
int add(int a,int b){
    return  a+b;
}
int main()
{
    A<int> a;
    A<float> a1;
    A<int *> a2;
    A<int(*)(int,int)> a3=add;
    return 0;
}

类实例>匹配的全特化模板>匹配的偏特化模板>基础模板

函数符(Function)

函数对象(Functor),仿函数

保存函数调用签名的形式:

  • 全局函数指针
  • 成员指针
  • 函数对象
  • lambda表达式

函数对象:是类对象,这个类对象的类中有一个小括号重载运算符函数。

#include <iostream>
using namespace std;
template<class T>
class A{
private:
    T str;
public:
    inline A(const T& t){
        this->str=t;
    }
    inline void  operator()(){
        cout << this->str << endl;
    }
};
void showInfo(){
    cout << "hello" << endl;
}
int main()
{
    showInfo();
    cout << "---------------------------------" << endl;
    A<string> a("functor is hello");
    a();
    return 0;
}

特点:

函数对象是类对象,当类对象调用成员函数时,函数符合内联条件,自动升级为内联函数,调用比普通函数效率高

函数对象可以直接使用类中定义的属性

函数对象具有具体的类型

函数对象一般不会单独使用,一般作为算法策略使用:

#include <iostream>
using namespace std;
template <class T>
T my_greate(T t1,T t2){
    return t1>t2?t1:t2;
}
template <class T>
T my_less(T t1,T t2){
    return t1<t2?t1:t2;
}
template <class T,class Compair>//Compair是获取到的函数类型 T是获取到的数据类型
T compair(T t1,T t2,Compair f){//Compair f=my_greate<int>
    return f(t1,t2);
}
//声明两个函数对象
template <class T>
class my_Greate{
public:
    T operator()(T t1,T t2){
        return t1>t2?t1:t2;
    }
};
template <class T>
class my_Less{
public:
    T operator()(T t1,T t2){
        return t1<t2?t1:t2;
    }
};
int main()
{
    int a=10,b=20;
    cout << "获取较大的值" << compair(a,b,my_greate<int>) << endl;
    cout << "获取较小的值" << compair(a,b,my_less<int>) << endl;
    cout << "使用函数对象,提高调用效率" << endl;
    cout << "获取较大的值" << compair(a,b,my_Greate<int>()) << endl;
    cout << "获取较小的值" << compair(a,b,my_Less<int>()) << endl;
    return 0;
}

函数对象术语

当函数对象的类中的小阔号运算符只有一个形参,所定义对象时,这个对象叫做一元函数对象

当函数对象的类中的小阔号运算符只有二个形参,所定义对象时,这个对象叫做二元函数对象

当函数对象的类中的小阔号运算符有多个形参,所定义对象时,这个对象叫做多元函数对象

当函数对象的类中的小阔号运算符返回值时一个bool类型,这个对象叫做谓词(Predicate)

匿名函数对象Lambda表达式

Lambda表达式分析:

  • []是函数对象的构造函数中的形参,获取外部实参时传递的形式
  • []为空时,代表无参的空构造,对于lambda不进行捕获
  • [=]相当于函数对象中的类中的构造函数为拷贝传参(值的传递)
  • [&]相当于函数对象中的类中的构造函数为引用传递(别名)
  • ()相当于小阔号运算符的形参列表
  • {}相当于括号运算符的函数体
  • 在lambda的形参列表后使用->返回值类型,明确返回值的类型
#include <iostream>
using namespace std;
class Lambda{
private:
//    int _a;
    int& _b;
public:
//    Lambda(){
//    }
//    Lambda(int& a){
//        //相当于构造函数中是一个值的拷贝
//        this->_a=a;
//    }
    Lambda(int& b):_b(b){
        //相当于构造函数中是一个值的拷贝
        this->_b=b;
    }
    void operator()(){
        cout << "hello world!" << endl;
    }
};
int main()
{
    //c++11 auto关键字:表示由编译器自动推导出的数据类型。不可作为函数形参
    auto f=[](){cout << "hello world" << endl;};
    f();
//    Lambda()();
//    auto f1=Lambda();
//    f1();
//    int a=100;
//    auto f2=[=](){
//        cout << a << endl;
//    };
//    f2();
    int b=10;
    cout << "b的地址:" << &b << endl;
    auto f3=[&](){
        cout << "b的地址:" << &b << endl;
    };
    f3();
    int x=100,y=200;
    auto f4=[&]()mutable{//mutable易变关键字,与const关键字相反
        int temp=x;
        x=y;
        y=temp;
    };
    f4();
    cout << "x=" << x << "  y=" << y << endl;
    return 0;
}

包装器

类模板std::function 是通用的多态函数封装器。 std::function 的实例能存储、复制及调用任何可调用对象。C++语言中有多种可调用对象:函数、函数指针、lambda表达式、bind创建的对象以及重载了函数调用运算符的类(仿函数)等。

和其他对象一样,可调用对象也有类型。如:每个lambda有它自己唯一的(未命名)类类型;函数及函数指针的类型则由其返回值类型和实参类型决定。然而,不同类型的可调用对象可能共享同一种调用形式。调用形式指明了返回的类型以及传递给调用的实参类型。一种调用形式对应一个函数(function)类型。

标准使用:

#include <iostream>
#include <functional>
using namespace std;
int add(int a,int b){//add函数类型:int (int ,int )
    return a+b;
}
class A{
public:
    int add(int a,int b){//int A::(A* const,int,int)
        return a+b;
    }
};
class B{
public:
    int operator()(int a,int b){//int A::(int,int)
        return a+b;
    }
};
int main()
{
    //使用标准包装器function包装全局函数
    function<int (int,int)> f1=add;
    cout << f1(10,20) << endl;
    //使用标准包装器function包装类成员函数
    A a;
    function<int(A* const,int,int)> f2=&A::add;
    cout << f2(&a,20,30) << endl;
    //使用标准包装器function包装一个函数对象
    function<int(int,int)> f3=B();
    cout << f3(10,20) <<endl;
    //使用标准包装器function包装一个Lambda表达式
    function <int (int,int)> f4=[](int a,int b){return a+b;};
    cout << f4(100,220) << endl;
    return 0;
}

封装一个包装器:

#include <iostream>
#include <functional>
using namespace std;
template <class T>
class My_function{
public:
    My_function(){
        cout << "my_function is basics" << endl;
    }
};
//模板偏特化
template<class Ret,class Arg1,class Arg2>
class My_function<Ret (Arg1,Arg2)>
{
private:
    //typedef Ret(*Pfunc)(Arg1,Arg2);
    using Pfunc=Ret (*)(Arg1,Arg2);
    Pfunc f;
public:
    My_function(Pfunc f){
        this->f=f;
    }
    //包装器核心
    Ret operator()(Arg1 arg1,Arg2 arg2){
        return f(arg1,arg2);
    }
};
int add(int a,int b){//类型 int (int ,int)
    return a+b;
}
int main()
{
    My_function<int (int,int)> f1=add;
    cout << f1(10,20) << endl;
    std::function<int(int,int)> f2=add;
    cout << f2(20,40) << endl;
    return 0;
}

到此这篇关于C++泛型编程综合讲解的文章就介绍到这了,更多相关C++泛型编程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++泛型编程综合讲解

本文链接: https://lsjlt.com/news/175862.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++泛型编程综合讲解
    目录函数模板类模板函数符(Function)包装器函数模板 进一步把函数中的或类中的数据类型进一步抽象,这个抽象的类型就叫泛型 模板:函数模板,类模板 模板就是把函数(或类)中的类型...
    99+
    2022-12-26
    C++泛型编程 C++泛型
  • C#泛型编的实例讲解
    本篇内容介绍了“C#泛型编的实例讲解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C# 泛型编程实例:using System;&...
    99+
    2023-06-17
  • C++超详细讲解泛型
    目录1.了解泛型编程2.函数模板2.1简单示例2.2多个模板参数2.3模板实例化2.4模板和普通函数同时存在2.5函数模板不支持定义和声明分离3.类模板3.1简单示例3.2成员函数声...
    99+
    2024-04-02
  • C#泛型编程介绍
    例子代码: 复制代码 代码如下:class Program    {       ...
    99+
    2022-11-15
    C#泛型
  • C++泛型编程基本概念详解
    目录1.什么是泛型编程?2.函数模板(1)函数模板概念(2)函数模板格式(3)函数模板的原理(4)函数模板的实例化(5)模板参数的匹配原则3.类模板(1)类模板的定义格式(2)类模板...
    99+
    2024-04-02
  • C++primer超详细讲解泛型算法
    目录初识泛型算法只读算法写容器算法定制操作lambda表达式lambda捕获和返回再探迭代器插入迭代器iostream迭代器反向迭代器初识泛型算法 只读算法 只读取输入范围内的函数,...
    99+
    2024-04-02
  • C++泛型模板约束深入讲解
    CPP参考:(新标准) 传送门 模板对于类型的约束: 约束 template_get_size 泛型T只允许接受类型:list<T>,其实为 C/C++ 泛型模板例化特性...
    99+
    2024-04-02
  • C#程序中怎么使用泛型集合代替非泛型集合
    C#程序中怎么使用泛型集合代替非泛型集合,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。软件开发过程中,不可避免会用到集合,C#中的集合表现为数...
    99+
    2024-04-02
  • 一文详解C++模板和泛型编程
    目录模板的定义模板的实例化类模板模板元编程总结模板的定义 C++中的模板和泛型编程是非常重要的概念。模板是一种将数据类型作为参数的通用程序设计方法。它们允许开发人员编写可以处理各种数...
    99+
    2023-05-20
    C++模板泛型编程 C++ 泛型编程
  • C#泛型集合类System.Collections.Generic
    目录一、定义泛型类二、从泛型类继承三、定义泛型运算符四、定义泛型结构五、定义泛型接口六、定义泛型方法1、普通类2、泛型类七、定义泛型委托1、通过泛型委托,委托的参数可以在以后定义。2...
    99+
    2024-04-02
  • C++ 函数模板详解:面向对象和泛型编程的融合
    函数模板融合了面向对象编程和泛型编程,允许创建可重用、面向不同数据类型的代码:面向对象:通过类和对象组织代码,函数模板使面向对象代码更灵活,可为不同类型编写函数版本。泛型:独立于特定数据...
    99+
    2024-04-26
    c++ 函数模板 字符串数组
  • C++泛型编程Generic Programming的使用
    目录一、容器 array vector deque list map 键值对key/value 二、迭代器iterator(泛型指针) 三、泛型算法Generic Programmi...
    99+
    2024-04-02
  • C++ 函数模板和泛型编程
    c++++ 函数模板和泛型编程允许创建可接受不同类型数据的通用代码,通过类型参数和模板类实现类型无关性。优点包括代码可重用性、类型安全和性能优化。通过函数模板(如“print”)和泛型类...
    99+
    2024-04-13
    泛型编程 函数模板 c++
  • 基于C语言实现泛型编程详解
    目录心理历程轮子用法大体流程部分源码心理历程 写了一段时间C++后,真心感觉STL里的容器是个好东西。一个容器可以容纳任意类型,容器对外的接口可以操作任意类型的数据,甚至包括自定义类...
    99+
    2024-04-02
  • Java多线程编程综合案例详解
    目录Java多线程综合案例数字加减生产电脑竞争抢答Java多线程综合案例 数字加减 设计4个线程对象,两个线程执行减操作,两个线程执行加操作 public class ThreadD...
    99+
    2024-04-02
  • 模板库和泛型库在 C++ 泛型编程中的作用?
    模板库和泛型库通过允许数据类型参数化和提供预定义的模板来实现泛型编程,提高了代码的可复用性和灵活性,包括:模板库:提供模板声明机制,创建根据数据类型参数化的类型或函数,例如 std::v...
    99+
    2024-04-24
    c++ 泛型编程
  • Swift泛型Generics浅析讲解
    目录泛型(Generics)汇编分析泛型的实现原理关联类型(Associated Type)类型约束协议类型的注意点泛型解决不透明类型(Opaque Type)泛型(Generics...
    99+
    2024-04-02
  • C#泛型详解
    这篇文章主要讲解C#中的泛型,泛型在C#中有很重要的地位,尤其是在搭建项目框架的时候。 一、什么是泛型 泛型是C#2.0推出的新语法,不是语法糖,而是2.0由框架升级提供的功能。 我...
    99+
    2024-04-02
  • 泛型编程在 C++ 中与设计模式的结合应用
    泛型编程和设计模式在 c++++ 中的结合提供了创建可重复、灵活且可扩展代码的方法。泛型容器(如 std::vector)允许存储任何类型的数据。泛型算法(如 std::sort)可用于...
    99+
    2024-05-14
    设计模式 泛型编程 c++
  • C++ 函数模板详解:泛型编程的本质解析
    函数模板是 c++++ 中的泛型编程特性,允许创建通用的函数以处理不同类型参数,提高代码灵活性、可重用性和简洁性:定义:函数模板提供函数签名,使用类型参数指定函数操作的数据类型。使用:通...
    99+
    2024-04-26
    c++ 函数模板
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作