简述C++泛型化编程思想

简述C++泛型化编程思想

 https://blog.csdn.net/Mary19920410/article/details/61914091

1、泛型的基本思想

泛型编程(Generic Programming)是一种语言机制,通过它可以实现一个标准的容器库。像类一样,泛型也是一种抽象数据类型,但是泛型不属于面向对象,它是面向对象的补充和发展。泛型编程在C++上的应用主要体现在两方面:函数模板和类模板,接下来我们通过两个例子说明。

1)函数模板

泛型,也就是我们说的任何类型,即不依赖于任何具体的类型。通常我们的操作都是依赖于具体的数据类型的,比如:

 

 
  1. int add(int a, int b)

  2. {

  3. return a + b;

  4. }


这个add函数依赖于int类型。你只能以int类型调用(即使是float,也会被转换为int型)。得到的结果也只能是int。那如果我们还需要一个float类型的add算法,就需要再写一个重载程序:

 

 

 
  1. float add(float a, float b)

  2. {

  3. return a + b;

  4. }

 

虽然在C++中可以通过函数重载来解决这个问题,但是反复写相同算法的函数是比较辛苦的,更重要的是函数重载是静态编译,运行时占用过多内存。

而泛型依赖于模板技术,可以支持任意数据类型,比如:

 

template <class T>
 
  1. T add( T a, T b)

  2. {

  3. return a + b;

  4. }

 

这个函数就可以用int,float等类型进行实例化,然后进行调用,这就不依赖任何具体的数据类型。例如:

 

 
  1. int result = add<int>(1,2);

  2. string result = add<string>("hello","world");

 

2)类模板

比如对栈的描述:

class stack{

push(参数类型);  //入栈

pop(参数类型);  //出栈

如果把上面的伪代码看作算法描述,没问题,因为算法与参数类型无关。但是如果把它写成可编译的源代码,就必须指明类型,否则是无法通过编译的。使用重载来解决这个问题,即对N种不同的参数类型写N个push和pop算法,这样是很麻烦的。

若对上面的描述进行改造如下:

首先指定一种通用类型T,不具体指明是哪一种数据类型:

class stack<参数模板T>

{

push(T);  //入栈算法

pop(T);  //出栈算法

}

这里的参数模板T相当于一个占位符,当我们实例化stack时,T会被具体的数据类型替换掉。

若定义对象S为stack类型,在实例化S时若我们将T指定int型,则:

 

 
  1. class S

  2. {

  3. push(int); //入栈

  4. pop(int); //出栈

  5. }


这时,我们可以称class stack<参数模板T>是类的类,通过它可以生成具体参数类型不同的类。

 

综上,可以看出泛型在C++中的应用主要是模板函数和模板类。

2、定义模板函数

函数模板是一个独立于类型的函数,可以产生函数的特定类型版本。

 

模板定义以关键字template开始,后接尖括号括住的模板形参表。

模板形参可以是表示类型的类型形参(type parameter),也可以是表示常量表达式的非类型形参(nontype parameter)。如下面的程序中的T是类型形参。

 

 
  1. /*

  2. implement strcmp-like generic compare function

  3. */

  4. #include <iostream>

  5. #include <string>

  6. using namespace std;

  7.  
  8.  
  9. template <typename T> //类型形参,若多个类型形参,则<typename T1, typename T2>

  10. int compare(const T &v1, const T &v2)

  11. {

  12. if(v1 < v2) return -1;

  13. if(v2 < v1) return 1;

  14. return 0;

  15. }

  16.  
  17.  
  18. int main()

  19. {

  20. cout << compare(1,2) << endl;

  21.  
  22. string s1 = "hello", s2 = "world";

  23. cout << compare(s1, s2) << endl;

  24. return 0;

  25. }

 

使用函数模板时,编译器会将模板实参绑定到模板形参。编译器将确定用什么类型代替每个类型形参,用什么值代替每个非类型形参,然后产生并编译(称为实例化)该版本的函数。

上面的例子中,编译器用int代替T创建第一个版本,用string代替T创建第二个版本。

3、定义模板类

在定义的类模板中,使用模板形参作为类型或值的占位符,在使用类时再提供具体的类型或值。例如:

 

 
  1. template <typename T>

  2. class Queue

  3. {

  4. public:

  5. Queue();

  6. T &front();

  7. const T & front() const;

  8. void push(const T&);

  9. void pop();

  10. bool empty()const;

  11. private:

  12. //...

  13. };


与调用函数模板不同,实用类模板时,必须为模板形参指明指定数据类型,例如:

 

 

 
  1. Queue<int> qi; // Queue that holds ints

  2. Queue<string> qs; // Queue that holds strings

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值