C++入门第六篇---STL模板---string【上】string模板的介绍(上)

简介: C++入门第六篇---STL模板---string【上】string模板的介绍(上)

前言:

从这里开始,有了C++类和对象的铺垫,我们能够引入C++最为重要的一个工具–STL模板库,在STL模板库中,我们得以将许多C语言的语法的局限性完全打开,尤其是繁杂的字符串操作和对于自定义类型的处理,那么接下来,就让我们熟练STL模板的使用和模拟实现。

模板:关键字:template

何为模板?想象一下我们去超市购买的雪糕,从甜筒机里我们可以按照我们想要吃的得到各种口味的相同形状的甜筒雪糕,在这里,不同口味不同材料的冰激淋被一个统一的模板构造成相同的形状然后返回给我们,我们所关注的是最后我们冰激淋的样子,这便是一个面向对象的过程。而在C++中的模板也是如此:模板代表了一种通用的程序执行逻辑,不同类型的数据在模板里都会进行相同的操作,根据你传入的数据类型进行实际的调整,从而得到我们想要的结果。

1.模板的常见书写形式:

template<class T1(或者是typename T),class T2,class T3…>(注意,句尾没有分号,这说明模板不是完整的语句),这里的T不仅仅可以用T,用其他的字符也可以

1.在尖括号里面,我们可以定义一个或者多个模板变量,根据自己实际的需求去定义,比如你需要两个不同数据类型的数据相加或者比较大小。

2.模板语句之后必须只跟要使用模板的模板函数或者模板类,中间不要穿插其他的语句或者变量,这是因为模板不是语句它不是独立的,必须直接跟使用它的场景,否则一旦中间有分号,模板自动跟这个分号的语句识别为一组,下面的模板就会报错没有意义了

3.注意,与函数不同,模板里面传的是类型,而函数里面传的是变量,这个别搞错了

2.模板的分类:

模板根据其使用的场景,我们将其分成两类:

1.第一类为函数模板

2.第二类为类模板

下面我们分别介绍一下两种模板:

1.函数模板:

函数模板,即用于函数使用的模板类型,主要用于对函数体的程序进行模板的使用,大致的用法就是:

**模板声明后下一行直接跟函数定义即可。**如下:

template<class T>
T add(T x,T y)
{
  return x+y;
}

也可以这样:

template<class T1,class T2>
T2 add(T1 x,T2 y)
{
   return x+y;
}

这样,就可以分别传两种不同的数据类型的数据,但可能涉及到隐式转换的问题,所以我们最好不要这样,倘若非要这样,最好强转其中一个数据,比如在这里要返回int类型,倘若我传入的数据是5,5.5,那我就把强转为int类型,这样就不会出现结果的问题。

但是,倘若100个参数,我就得一个一个的去强转,那样太麻烦了,故我们可以这样:

template<class T>
T add(T x,T y)
{
  return x+y;
}
int main()
{
    cout<<add<int>(5,5.5)<<endl;
}

在这里,我们显式实例化函数模板,让对应的T变成固定的int类型,不管传入什么数据,都会被当成int类型处理这样,就可以避免数据类型不同产生的报错

故在这里,我们用两种方式来针对不同类型的参数的传入:

1.定义多个模板变量,然后分别占位
2.使用显式实例化,将所有的模板变量手动全部按照<>里面的数据类型处理

如下:

template<class T1,class T2>
 int add(T1 x, T2 y)
{
  return x + y;
}
int main()
{
  cout<<add<int>(1, 2.2);
  return 0;
 }
1.实例化:

何为实例化,首先我们要清楚,模板和类一样,本质上是一个蓝图,并不是实际占用空间的程序,而通过蓝图使变量被创建并使用的过程叫做实例化。

常见的实例化分为两种:

1.隐式实例化:即不是用户自己去定义的,而是计算机通过传入函数的参数推导出来的数据的类型并且对应使用的叫做隐式实例化
2.显式实例化:用户直接给模板规定的实例化的参数是什么,而不是计算机自己推出来的,一般在对应的位置加上<>里面写显式的变量类型,如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错

不管是函数,还是类,他们的实例化都是如此。

2.模板参数的匹配原则:

同名字和模板函数和普通的函数可以同时存在么?

由我们学到的函数重载的知识可知,T和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函数和普通的全局Add函数,他们是可以同时存在的,那我这里的Add(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<int>(1, 2);
}

调试如下:

我们发现,它就进入我们的模板函数,这是由于,我显式实例化了add,同时也起到了告诉编译器强制进入模板函数的意思,编译器发现反正都不需要推导,不如就进入你让我进入的那个函数,故就进入了模板函数。

故我们在这里总结模板函数的匹配原则:

1.一个非模板的函数可以和一个同名的模板函数同时存在,而且该模板函数还可以实例化这个非模板函数
2.对于非模板函数和同名的模板函数,如果其他条件都相同(包括参数个数,参数的数据类型这些,主要是看参数),那么在调用时会优先调用非模板函数而不是模板函数,但我们可以显式实例化使其强制调用模板,如果模板可以产生一个具有更好匹配的函数,那么编译器就会选择调用模板函数,这个更好匹配主要看你传入的参数类型是什么

3.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换,即哪怕是双目操作符两边的数据需要转换,也不会转换

2.类模板:

类模板的书写方式和函数一样,也是在类的前面加上template<class T1,class T2…>

但类的使用和函数不同,类必须要显式实例化,也就是必须要加<>在里面给具体的模板参数的类型是什么

!!!注意:类模板最为重要的一点,接触到模板后,我们要清楚一个概念:
在模板出现之前,类的名字就是其类型,但有了模板后,类的名字就是名字,类的类型是名字<显式实例化>,而不是单纯的名字,故我们在使用创建模板类的时候千万别忘了加<>显式实例化的内容,同时,模板类最好不要声明和定义分离,并不是不能,而是很容易错,因为涉及到这个<>有时候很容易错

例如:

// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

模板阶段总结:

现在,我们已经有了模板的概念并且清楚模板如何使用,模板的知识是我们接下来的STL模板库的一个重要的铺垫,一定要先弄明白再向下进行,否则对于模板库的理解会出现问题。

STL模板标准库介绍:

1.定义:

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。也就是说,通过模板库,我们只需要传参就可以实现对应的功能,不需要再像C语言那样自己手动构建这些框架和功能。

我们的STL大概分为四种版本:

2.版本:

1.原始版本

2.PJ版本

3.RW版本

4.SGI版本

而SGI版本由于可移植性好,被广泛使用,现在的很多STL资料基本都是SGI版本,全面而且阅读体验也很好,在这里我也用这个版本的STL库

3.STL的具体内容:

STL主要分为一下的内容:

首先,这里的容器就是数据结构,这个是最容易被误解的东西,其实容器本质上就是存储数据的,加容器也无可厚非。

3.STL的一些问题:

1.STL库写的非常的冗余,很多功能的配置本质上是不需要的,这也是因为很多人为了自己的需求而不断去扩展导致的。

2.STL内部实现很复杂,设计迭代器一些东西

3其实STL的问题还有很多,但是介于我们目前所学,这两点是我们首先应该对STL有的一个大致的概念

我会在后面附上:

正如我今天的标题所说,我们首先会进入STL最常见的第一个模板:string模板,即字符串操作模板

string模板:

依旧是我们经常使用的思维方式:

让我们先想想我们C语言字符串方面的问题:在C语言中,字符串以\0结尾,C语言提供了一系列操作字符串的函数,但问题在于函数的功能太过单一,不够全面,而且很容易出现访问越界的问题,通俗来讲就是用户需要管理底层,从而导致访问大量越界。而C++则直接让用户关注于字符串本身,大量的成员函数保证了其功能的完整。

1.string模板的介绍:

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

** 针对string的特性,我们这样总结:

a.string是表示字符串的字符串类

b.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作

c.string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;

d. 不能操作多字节或者变长字符的序列。**

下面,我们针对string的几个重要的函数接口进行一下说明和使用:

注意,使用string类模板需要我们引用头文件#include< string >同时要开放官方命名空间std

#include< string >
using namespace std;

1.构造类:

1.构造函数:

在这里我们常用的是无参或者一个字符串或者一个字符串的一部分,在这里我们看所给的函数的具体实现的,我们从函数的具体参数可以知道,构造是支持传入无参空字符,一个字符,一个字符串(const或者非const),一个字符串的前几位,一个字符串的起始点到中止点的一部分,或者指定长度改为一个字符去创建字符串。具体要看我们要实现怎样的功能。

这里的第2个就是拷贝构造函数千万别混淆,拷贝构造也是构造函数的一种

2.析构函数:

这个析构函数和我们类和对象里面的析构函数差不多,我们具体在析构函数里面实现我们要资源清理的内存,这里不过多阐述,主要就是当有动态内存被开辟的时候,我们的析构函数就必须要显式书写对应的内存释放的析构函数。

3.赋值运算符重载:

这个赋值运算符重载和之前讲的赋值运算符重载,**倘若两个已经被创建出来的string类,就直接调用赋值运算符重载,倘若为未创建的string类,则直接调用拷贝构造函数创建变量,**这里有很多的细节,为了不影响我们的主体内容,在这里我们先不介绍,我会在本篇的最后补充着部分的知识。

2.类对象的容量操作类

1.size函数/length函数:

在这里设置size是可以用来返回字符串的长度的,和strlen一样,size也不会把\0计入到长度中,由于_size是private的成员函数,故没法直接访问,故只能通过函数待会得到长度。

length和size的用法相同,只不过以前叫length,经过更新引入了size,其具体的函数用法都一模一样。

2.capacity函数:

capacity函数是用来返回字符串的内存大小的,这个和size不一样,size是实时控制字符串的长度,而capacity不管是否插入数据,其内存都存在,capacity就是用来记录这个内存的大小的,一个字符串的长度可能为4,但它开辟的空间可能要大于4,但绝对不能小于4.

目录
相关文章
|
1天前
|
C++ 编译器 程序员
C++ 从零基础到入门(3)—— 函数基础知识
C++ 从零基础到入门(3)—— 函数基础知识
|
1天前
|
C++ 存储
C++从零基础到入门(2)—— (if、switch、for、while语句)
C++从零基础到入门(2)—— (if、switch、for、while语句)
C++从零基础到入门(2)—— (if、switch、for、while语句)
|
5天前
|
编译器 C语言 C++
C++入门基础-2
C++入门基础
12 3
|
5天前
|
C语言 C++
C++入门基础-1
C++入门基础
18 1
|
5天前
|
存储 C++ 容器
C++:STL - set & map
C++:STL - set & map
14 4
|
6天前
|
编译器 C++
【C++】继续学习 string类 吧
首先不得不说的是由于历史原因,string的接口多达130多个,简直冗杂… 所以学习过程中,我们只需要选取常用的,好用的来进行使用即可(有种垃圾堆里翻美食的感觉)
7 1
|
6天前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
15 0
|
1天前
|
Java 编译器 ice
【Java开发指南 | 第十五篇】Java Character 类、String 类
【Java开发指南 | 第十五篇】Java Character 类、String 类
11 1
|
5天前
|
安全 Java 编译器
Java中String、StringBuilder和StringBuffer的区别
Java中String、StringBuilder和StringBuffer的区别
10 1