C++泛型编程综合讲解

泛型编程与面向对象编程的目标相同,即使重用代码和抽象通用概念的技术更加简单。但是面向对象编程强调编程的数据方面,泛型编程强调的是独立于特定数据类型

函数模板

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

模板:函数模板,类模板

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

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

模板编译机制:

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

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

关键字template是模板标识符

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

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

#include  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 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(a2,b2) << endl;//显示调用 return 0; }

显示调用和隐式调用

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

函数模板的特化

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

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

#include  using namespace std; template   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  using namespace std; template   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  using namespace std; template   T compair(T t1,T t2){ cout << "i am is basics" <t2?t1:t2; } //对基础模板进行全特化(函数模板只能全特化,不能偏特化) template <> const char* compair(const char* str1,const char* str2){ cout << "i am is specialization" <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(str1,str2) << endl; cout << compair(a,b) << endl; return 0; } 

函数模板的实参推演

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

#include  using namespace std; template   T add(T t1,T t2){ cout << "i am is one_basics" < T1 add(T1 t1,T2 t2){ cout << "i am is two_basics" <

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

#include  #include //信息识别头 using namespace std; template  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  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  using namespace std; //函数实例 void print(){ }; template  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  using namespace std; template  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 Stu:public Person { private: const T3 _id; static int count; public: Stu(T1 name,T2 age,T3 id):Person(name,age),_id(id){ count++; } void showInfo()override{ cout << "学号:" << this->_id << ",姓名:" << this->getName() << ",年龄:" << this->getAge() << endl; } static int get_count(){ return count; } }; template  int Stu::count=0; int main() { Person *person=new Stu("yao",19,1); person->showInfo(); delete person; Stu stu("sunsun",18,2);//使用缺省类型,从右往左 stu.showInfo(); cout << Stu::get_count() << endl; return 0; } 

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

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

stack_cpp.hpp:

#ifndef MY_STACK_HPP #define MY_STACK_HPP #include  #include  #include  using namespace std; template  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 my_stack::my_stack(int c) { this->capacity=c; this->m_data=new T[capacity]; this->size=0; } template my_stack::~my_stack() { if(nullptr!=this->m_data){ delete [] this->m_data; this->m_data=nullptr; } capacity=size=0; } template bool my_stack::full() { return size==capacity; } template bool my_stack::empty() { return size==0; } template void my_stack::push(const T &val) { if(full()){ return; } m_data[size]=val; size++; } template void my_stack::pop() { if(this->empty()){ throw range_error("空了"); } size--; } template T &my_stack::top() { return m_data[size-1]; } 

main.cpp:

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

内嵌类

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

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

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

类模板的特化

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

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

函数符(Function)

函数对象(Functor),仿函数

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

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

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

#include  using namespace std; template 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 a("functor is hello"); a(); return 0; } 

特点:

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

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

函数对象具有具体的类型

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

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

函数对象术语

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

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

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

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

匿名函数对象Lambda表达式

Lambda表达式分析:

  • []是函数对象的构造函数中的形参,获取外部实参时传递的形式
  • []为空时,代表无参的空构造,对于lambda不进行捕获
  • [=]相当于函数对象中的类中的构造函数为拷贝传参(值的传递)
  • [&]相当于函数对象中的类中的构造函数为引用传递(别名)
  • ()相当于小阔号运算符的形参列表
  • {}相当于括号运算符的函数体
  • 在lambda的形参列表后使用->返回值类型,明确返回值的类型
#include  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  #include  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 f1=add; cout << f1(10,20) << endl; //使用标准包装器function包装类成员函数 A a; function f2=&A::add; cout << f2(&a,20,30) << endl; //使用标准包装器function包装一个函数对象 function f3=B(); cout << f3(10,20) < f4=[](int a,int b){return a+b;}; cout << f4(100,220) << endl; return 0; }

封装一个包装器:

#include  #include  using namespace std; template  class My_function{ public: My_function(){ cout << "my_function is basics" << endl; } }; //模板偏特化 template class My_function { 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 f1=add; cout << f1(10,20) << endl; std::function f2=add; cout << f2(20,40) << endl; return 0; }

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

以上就是C++泛型编程综合讲解的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » C语言