日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++泛型編程綜合講解_C 語言

作者:編程遠泊 ? 更新時間: 2023-02-01 編程語言

函數模板

進一步把函數中的或類中的數據類型進一步抽象,這個抽象的類型就叫泛型

模板:函數模板,類模板

模板就是把函數(或類)中的類型抽象出來,有指定類型方可使用

模板可以有默認類型,類模板規則(函數模板,不存在規則):從右到左

模板編譯機制:

  • 編譯器并不是把函數(類)模板處理成能夠處理任何類型的函數(類),而是一個函數(類)的生成器。
  • 函數(類)模板通過具體類型產生不同的函數實例(類實體)。
  • 編譯器會對函數(類)模板進行兩次編譯,第一次在聲明的地方對模板本身進行編譯(主要是對語法進行檢查,在調用的地方對參數替換),再次對代碼進行編譯,二次編譯也被稱之為延時編譯。

注意:模板函數需要編譯兩次,是慢于定義函數的原因

關鍵字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;
}

原文鏈接:https://distant-rove.blog.csdn.net/article/details/128288364

欄目分類
最近更新