【C++】STL和模板初阶

【C++】STL和模板初阶

前言:

这节学的是STL,不懂STL,就不要说懂C++!有了STL,许多的数据结构以及算法都不需要自己重新造轮子。

一、STL简介

1.1 什么是STL

概念:STL(standard template libaray 标准模板库),是C++标准模板库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

1.2 STL的版本

  • HP STL:最初由惠普公司开发,是STL的早期版本,为C++标准模板库的发展奠定了基础,是开源的,是所有STL实现版本的始祖。
  • P.J.STL:由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改。
  • RW STL:由Rouge Wage公司开发,继承自HP版本,被C++ Builder采用,不能公开或修改,可读性一般。
  • SGI STL:由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程风格来看,阅读性非常高。

1.3 STL的重要性

  • 泛型编程支持:利用模板实现高度抽象与复用,能编写与数据类型无关的通用代码,提高灵活性和扩展性。
  • 高效的数据结构与算法:有 vector 、map 等多种数据结构,还包含大量优化过的经典算法,可优化性能,具备良好的时间和空间复杂度
  • 统一规范与接口:为容器和算法制定统一接口与操作规范,使代码风格统一,利于团队协作开发。

1.4 STL的六大组件

STL
仿函数
算法
迭代器
空间配置器
容器
配接器

二、模板初阶

2.1 泛型编程

概念:编写与类型无关的通用代码,是代码服用的一种手段。模板是泛型编程的基础。

示例:当我们写一个交换函数(swap),要如何实现呢?

首先想到的是用函数重载,函数重载的概念是,在同一作用域内,可以有多个同名函数,但在这些函数的参数列表(参数个数,参数类型或参数顺序)必须不同。

代码:

void swap(int& i, int& j)
{
	int tmp = i;
	i = j;
	j = tmp;
}
void swap(double& i, double& j)
{
	int tmp = i;
	i = j;
	j = tmp;

}

以上的函数重载虽然可以实现,但是代码很像,后期使用这样的代码的时候,是否要写这么多个,而且维护起来很难。那么要用这样的代码的时候,我们告诉编译器一个模板就好了。

模板分类:

模板
函数模板
类模板

2.2 函数模板

  • 概念:函数模板代表了一个函数家族,函数模板就是一个公式,可用来生成针对特定类型的函数版本。
  • 函数模板格式:
template<typename T1, typename T2,......,typename Tn>

返回值类型 函数名(参数列表){}

代码例子:

template<typename T>
void Swap( T& left,  T& right)
{
 T temp = left;
 left = right;
 right = temp;
}

注意:typename是用来定义模板参数关键字,也可以使用class(但不能用struct代替class)

2.3 实例化函数模板

概念:用不同类型的参数使用函数模板时,称为函数模板实例化。实例化分为隐式实例化和显式实例化

  • 隐式实例化:让编译器根据实参推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
    int a1 = 10, a2 = 20;
    double d1 = 10.0, d2 = 20.0;
    Add(a1, a2);
    Add(d1, d2);
    cout << Add(a1, a2) << endl;
    return 0;
}
  • 显式实例化:在函数名后的<>中指定模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main(void)
{
    int a = 10;
    double b = 20.0;
    
    // 显式实例化
    Add<int>(a, b);
    return 0;
}

要是遇到两个参数类型不同,有两种解决方法,一是程序员自己强转一下类型,二是显式实例化。

int main()
{
    int a1 = 10, a2 = 20;
    double d1 = 10.0, d2 = 20.0;
    Add(a1, a2);
    Add(d1, d2);

    Add(a1, (int)d1);
    Add<int>(a1, d2);
    
    cout << Add(a1, a2) << endl;
    cout << Add(a1, (int)d1) << endl;
    cout << Add<int>(a1, d2) << endl;
    
    return 0;
}
2.3.1 模板参数匹配原则
  • 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
  int Add(int left, int right)
 {
      return left + right;
 }
  
  // 通用加法函数
  template<class T>
  T Add(T left, T right)
 {
      return left + right;
 }
  
  void Test()
 {
      Add(1, 2);       // 与非模板函数匹配,编译器不需要特化
      Add<int>(1, 2);  // 调用编译器特化的Add版本
 }

  • 对于非模板函数和同名函数模板,若其他条件都相同,在调动时会优先调用非模板函数。若模板可以产生一个具有更好匹配的函数,那么将选择模板。

     int Add(int left, int right)
     {
          return left + right;
     }
      
      // 通用加法函数
      template<class T>
      T Add(T left, T right)
     {
          return left + right;
     }
     void Test()
     {
          Add(1, 2);     // 与非函数模板类型完全匹配,不需要函数模板实例化
          Add(1, 2.0);   // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的
    Add函数
     }
    
    

2.4 类模板

  • 概念:类模板是用来生成蓝图的。与函数模板不同的是,编译器不能为类模板推断模板参数类型。
  • 类模板的定义格式:
template<class T1, class T2, ..., class Tn> 
class 类模板名
{
 // 类内成员定义
};

代码示例:

// 类模版
template<typename T>
class Stack
{
public:
    Stack(size_t capacity = 4)
    {
        _array = new T[capacity];
        _capacity = capacity;
        _size = 0;
    }
    void Push(const T& data);
 private:
    T* _array;
    size_t _capacity;
    size_t _size;
};

注意:类模板不建议声明和定义分离到两个文件.h和.cpp中,会出现链接错误,具体原因如下:

  • 编译实例化困难:类模板的实例化依赖于编译器同时看到声明和定义,分离后链接时编译器难以找到模板的完整定义,导致无法正确实例化模板。
  • 链接错误:在链接阶段,链接器可能找不到模板实例化所需的符号,从而产生链接错误,尤其在有多个源文件的情况下。

2.5 类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

// Stack是类名,Stack<int>才是类型
Stack<int> st1;    // int
Stack<double> st2; // double
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值