泛型编程

1. 了解什么是泛型

编程范式的英语是 programming paradigm,范即模范之意,范式即模式、方法,是一类典型的编程风格,是指从事软件工程的一类典型的风格(可以对照“方法学”一词)。

编程语言发展到今天,出现了好多不同的代码编写方式,但不同的方式解决的都是同一个问题,那就是如何写出更为通用、更具可重用性的代码或模块。
C 语言的泛型
一个泛型的示例 - swap 函数
好了,我们再看下,C 语言是如何泛型的。C 语言的类型泛型基本上来说就是使用void *关键字或是使用宏定义。

下面是一个使用了void*泛型版本的 swap 函数。

void swap(void* x, void* y, size_t size)
{
     char tmp[size];
     memcpy(tmp, y, size);//内存复制
     memcpy(y, x, size);
     memcpy(x, tmp, size);
}

上面这个函数几乎完全改变了 int 版的函数的实现方式,这个实现方式有三个重点:

函数接口中增加了一个size参数。为什么要这么干呢?因为,用了 void* 后,类型被“抽象”掉了,编译器不能通过类型得到类型的尺寸了,所以,需要我们手动地加上一个类型长度的标识。

函数的实现中使用了memcpy()函数。为什么要这样干呢?还是因为类型被“抽象”掉了,所以不能用赋值表达式了,很有可能传进来的参数类型还是一个结构体,因此,为了要交换这些复杂类型的值,我们只能使用内存复制的方法了。

函数的实现中使用了一个temp[size]数组。这就是交换数据时需要用的 buffer,用 buffer 来做临时的空间存储。
于是,新增的size参数,使用的memcpy内存拷贝以及一个 buffer,这增加了编程的复杂度。这就是 C 语言的类型抽象所带来的复杂度的提升。

在提升复杂度的同时,我们发现还有问题,比如,我们想交换两个字符串数组,类型是:char*,那么,我的swap()函数的x和y参数是不是要用void**了?这样一来,接口就没法定义了。

除了使用 void* 来做泛型,在 C++ 语言中,还可以用宏定义来做泛型,如下所示:

#include
#include
#include
#include
#include
#define swap(x, y, size)  {\
    char temp[size]; \
    memcpy(temp, &y, size); \
    memcpy(&y,   &x, size); \
    memcpy(&x, temp, size); \
}
using namespace std;

int main() 
{
    int x=2;int y=1;
    swap(x,y,sizeof(int));
    cout<return 0;
}

C++ 对 C 语言的贡献非常之大。是的,C++ 很大程度就是来解决 C 语言中的各种问题和各种不方便。比如:

  1. 用引用来解决指针的问题。
  2. 用 namespace 来解决名字空间冲突的问题。
  3. 通过 try-catch 来解决检查返回值编程的问题。
  4. 用 class 来解决对象的创建、复制、销毁的问题,从而可以达到在结构体嵌套时可以深度复制的内存安全问题。
  5. 通过重载操作符来达到操作上的泛型。(比如,消除上一篇文章中提到的比较函数cmpFn,再比如用>>操作符消除printf()的数据类型不够泛型的问题。)
  6. 通过模板 template 和虚函数的多态以及运行时识别来达到更高层次的泛型和多态。
  7. 用 RAII、智能指针的方式,解决了 C 语言中因为需要释放资源而出现的那些非常 ugly 也很容易出错的代码的问题。
  8. 用 STL 解决了 C 语言中算法和数据结构的 N 多种坑。

你可能感兴趣的:(c++)