c++复习日记3 模板和流

8月18日复习了模板和流的相关内容。

模板,简单地说就是一个“多功能”的程序模块。这个模块的输入,不限定某一个类型。

具体来说,对于模板函数,传入参数的数据类型可以不固定,但逻辑结构要相同。模板函数说明可以写为:

template <typename 类型形参>;
返回类型(可以是类型形参) 函数名(类型形参 参数名A,类型形参 参数名B);

参数A和B可以是不固定的类型。调用时如果使用:

cin>>a>>b;
cout<<函数名(a,b);

那么在调用这个函数时,编译器将调用参数类型为输入的a和b的数据类型的重载版本的函数。这个过程也就是实例化。这样一来,就可以避免在对数据类型不同的操作对象进行逻辑相同的操作时,程序员还需要再写一个仅仅参数类型不同的函数的问题了。

函数模板实例化时,如果进行替换的实际参数有多个,他们类型不相同,却要进行加减、比较等操作,模板机制不会提供参数类型自动转换。也就是说:

template <typename a>;
a compare(const a x,const a y) {return x>y?x:y;}

如果有参数int x和char y,那么调用函数模板在实例化时将会报错“参数类型无法匹配”。这时需要人为的进行一个重载:

int compare(const int x,const char y);

那么编译器可以进行隐式类型转换,这时再调用函数,无论是char类型在前还是int类型在前,都就可以正常执行了。

除了有函数模板,还有类模板。在定义类前说明一个类属类型,用这个类型去定义类中的一些函数成员或者数据成员。类模板的实例化和函数模板的实例化类似,都是赋予一个具体的数据类型。类模板可以作为函数参数,也可以在作为派生类从类模板派生或普通类派生。模板类也可以从类模板派生或普通类派生。从类模板派生模板类的例子:

#include <iostream>
using namespace std;
template <typename a>
class Base       //定义基类:类模板
{
public:
    Base(a x) {xx = x;}
    void out() { cout << xx << endl; }
protected:
    a xx;
};
class First :public Base<int>   //派生模板类
{
public:
    First(int y, double yy) :Base<int>(y) { k=yy; }
    void out() { Base<int>::out();cout << k << endl; }
protected:
    double k;
};
int main()
{
    Base<int> data1(3);
    data1.out();
    First data2(1, 2);
    data2.out();
}

标准模板库STL主要组件有容器、迭代器和算法。容器是数据结构:

序列容器:vector向量、deque双向队列、list双向链表

关联容器:set集合、multiset集合((允许重复值元素)、map映射、multimap映射(允许重复值元素)

容器适配器:stack堆栈(LIFO)、queue队列(FIFO)、pirority_queue优先队列

对容器有一些共同的操作:

Container c(beg,end) 以beg地址为起点,到地址end的数据序列作为初值构造容器

c.size() 返回容器元素个数

c.begin() c.end() 顾名思义

c.insert(pos,elem) 在迭代器pos所指位置前插入elem

c.clear() 清空容器

还有一些序列容器特有的操作:

c.front() /c.back() 访问容器首/尾元素数据

c.push_back(elem)/c.pop_back() 插入/删除尾元素数据

c[i] 访问第i个元素

下面是一个STL容器操作的例子:

#include <iostream>
#include <list>
#include <cstdlib>
#include <ctime>
using namespace std;
//建立有序链表
void creatList(list<int>& orderList, int Len)
{
    int i, k;
    for (i = 0;i < Len;i++)
    {
        k = rand() % 100;   //生成多个随机数
        orderList.push_back(k);  //插入容器末尾
    }
    orderList.sort();        //排序
};
//输出链表
void outList(list<int>& List)
{
    list<int>::iterator p;  //建立迭代子p
    p = List.begin();
    while (p != List.end())
    {
        cout << *p << " ";
        p++;
    }
    cout << "\r\n";
​
};
//合并链表
void inorderMerge(list<int>& A1, list<int> A2)
{
    A1.merge(A2);
};
int main()
{
    list<int> A1, A2;
    srand(int(time(0)));  //初始化随机序列起点
    creatList(A1, 10);
    outList(A1);
    cout << endl;
    creatList(A2, 5);
    outList(A2);
    cout << endl;
    inorderMerge(A1, A2);
    outList(A1);
}

迭代子好比一个可以指向容器内元素的指针,可以通过c.begin() c.end() 指向首尾。迭代子也有着类似指针的操作,*p是其所指向的对象。STL库定义了五种迭代器,输入、输出,正向、双向、随机访问。迭代器在头文件iterator中声明,但一般容器头文件已经包含,不用特地去声明。

STL库还包含了多种算法,常有的有find查找、find_if条件查找、sort排序等等。算法在头文件algorithm中声明。力扣的题凡是用到数组的地方,大多都会用vector向量代替,并调用STL库的操作。大概是因为在减少工作量的同时并不会显著升高算法复杂度。毕竟c++是效率之王。


最后一章,c++中的流。记得刚转专业后补修c++时,因为那个学期课程又多又难,学习c++也是囫囵吞枣,写代码只知道一开始就#include<iostream>,再来一个using namespace std;经常自己写完这两句,后面的写不下去了,就去CSDN用crtl+c大法,真是说来惭愧。久而久之,就这两句打起来最熟练,但打了这么多次,却不知道这两句是什么意思。iostream的头文件里包含了哪些东西?std又是一个什么样的命名空间?都没有去深究。

今天复习到这里,终于解开了当时的疑问。“流”指的是数据流,玩过单片机用过串口就知道,数据在主从机是怎么进行交互的。流主要指的是输入流和输出流,输入流是从键盘鼠标等设备流向内存,输出流是从内存流向显示器、打印机等等,这都是通过字节流实现,说的再直白些,就是一串八个八个的由“0”或“1”组成的比特流。

c++的流类库是用继承的方法建立起的一个类库,有两个平行的基类streambuf类和ios类。带buf的都跟缓存有关,ios类库则提供了高级的I/O操作。ios派生了两个类,就是比较熟悉的istream类和ostream类。他俩共同派生了iostream类,就是那个我经常无脑包含的头文件。iostream类也有三个派生类,是文件输入输出fstream类、串输入输出strstream类和标准输入输出stdiostream类。

常用的头文件除了iostream,还有iomanip,它包含了格式化I/O的带参数操纵算子,用于指定输入输出格式。头文件fstream处理文件有关信息。

标准流cin,cout,cerr和clog,前两个很熟悉,后两个是错误输出流,不能重定向。其中,输入流提取运算符>>有类型转换功能,可以把输入的空格、Tab转换成分隔符。而istream中一些函数可以实现特殊的提取功能,如get可以从流中提取字符包括空格,这也是为什么检测输入空格时经常用get。getline从流中提取一行字符;read无格式输入指定字节数。 输出流提供了成员函数put和write,可以在输出中插入字节或是字节序列。

输入输出流中有着格式控制的功能。ios提供了如dec(输入/输出转化为十进制)、showpoint(输出时显示小数点)等等格式控制标志常量,可以给用户提供方便的格式控制。iomanip中的格式控制符有我们常用的setw(控制输出宽度),还有setprecision(设置浮点数输出精度)等等。

串流可以连接string对象和字符串。使用串流类要包含sstream头文件,可以从string对象直接提取/插入数据。文件流可以进行对文件的开关读写,要包含fstream头文件,文件流类提供了直接操作文件的函数。虽然封装程度不比python,但也为用户提供了巨大便利。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值