C++提高编程(黑马程序员)

本阶段主要针对C++泛型编程和STL技术做详细讲解

1.模板

1.1 模板的概念

模板就是建立通用的模具,提高复用性

1.2函数模板

函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可不具体指定,用一个虚拟的类型来代表
语法:

template<typename T>
函数声明或定义

注:
template --声明创建模板
typename --表示其后面的符号是一种数据类型,可以用class代替
T --通用的数据类型,名称可以替换,通常为大写字母

// 两个整型交换
void swapInt(int &a, int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
// 交换两个浮点型
void swapDouble(double &a, double &b)
{
    double tmp = a;
    a = b;
    b = tmp;
}
void test01()
{
    int a = 10;
    int b = 20;
    swapInt(a, b);
    cout << a << endl;
    cout << b << endl;
    double c = 1.1;
    double d = 2.2;
    swapDouble(c, d);
    cout << c << endl;
    cout << d << endl;
}
// 函数模板
template <typename T> // 声明一个模板,后面代码中的T是一个通用的数据类型
void mySwap(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}
void test02()
{
    int a = 10;
    int b = 20;
    // 两种使用模板的方法
    // 1.自动类型推导
    mySwap(a, b);
    cout << a << endl;
    cout << b << endl;
    // 2.显示指定类型
    mySwap<int>(a, b);
    cout << a << endl;
    cout << b << endl;
}

int main()
{
    test02();
}

1.2.2 函数模板注意事项

注意事项:
-自动类型推到,必须导出一致的数据的数据类型T才可以使用
-模板必须要确定出T的数据类型,才可以使用

template <class T> // typename 可以用class替换
void mySwap(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}
void test01()
{
    int a = 10;
    int b = 20;
    char c = 'c';
    mySwap(a, b);
    // 1.自动类型推导,必须推导出一致的数据类型T才可以使用
    // mySwap(a,c); 错误!
    cout << a << endl;
    cout << b << endl;
}
// 2.模板必须要确定T的数据类型才可以使用
template <class>
void func()
{
    cout << "func" << endl;
}
void test02()
{
    // func();//报错,没有给出T
    func<int>(); // 强行给定一个类型
}

int main()
{
    test02();
}

1.2.3 函数模板案例

案例描述:
-利用函数模板封装一个排序函数,可以对不同数据类型数组进行排序
-排序规则从大到小,排序算法为选择排序

  • 分别用char和int数组进行测试
template <class T> // typename 可以用class替换
void mySwap(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}
template <class T> // typename 可以用class替换
void mySort(T arr[], int len)
{
    for (int i = 0; i < len; i++)
    {
        int max = i; // 最大值的下标
        for (int j = i + 1; j < len; j++)
        {
            // 认定最大值比遍历的要小,说明j下标是真正的最大值
            if (arr[max] < arr[j])
            {
                max = j;
            }
        }
        if (max != i)
        {
            mySwap(arr[i], arr[max]);
        }
    }
}
template <class T>
void printArray(T arr[], int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << arr[i];
    }
}
void test01()
{
    char charArr[] = "badcfe";
    int num = sizeof(charArr) / sizeof(char);
    mySort(charArr, num);
    printArray(charArr, num);
    // int arr[];
}
void test02()
{
    int intArr[] = {2, 5, 1, 7, 8};
    int num = sizeof(intArr) / sizeof(int);
    mySort(intArr, num);
    printArray(intArr, num);
}
int main()
{
    test02();
}

1.2.4 普通函数和函数模板的区别

-普通函数调用时可以发生自动类型转换(隐式类型转换)

  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,可以发生隐式类型转换
int myAdd(int a, int b)
{
    return a + b;
}
template <class T>
T myAdd02(T a, T b)
{
    return a + b;
}
void test01()
{
    int a = 10;
    int b = 20;
    char c = 'c';
    cout << myAdd(a, b) << endl;   // 30
    cout << myAdd02(a, b) << endl; // 30
    cout << myAdd(a, c) << endl;   // 109,c对应的ASCII码99,相当于把字符型隐式的转换为int型
    // cout << myAdd02(a, c) << endl;错误!不会发生隐式类型转换
    // 显示指定类型
    cout << myAdd02<int>(a, c) << endl; // 109,发生隐式类型转换
}
int main()
{
    test01();
}

1.2.5 普通函数和函数模板的调用规则

1.如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板
注意:如果提供了模板,就不要提供普通函数版本,容易出现二义性

void myPrint(int a, int b)
{
    cout << "普通函数调用" << endl;
}
template <class T>
void myPrint(T a, T b)
{
    cout << "模板调用" << endl;
}
template <class T>
void myPrint(T a, T b, T c)
{
    cout << "重载的模板调用" << endl;
}
void test01()
{
    int a = 10;
    int b = 10;
    int c = 20;
    char d = 'a';
    char e = 'b';
    myPrint(a, b);    // 1.优先调用普通函数调用
    myPrint<>(a, b);  // 2.通过空模板强制调用模板
    myPrint(a, b, c); // 3.函数模板也可以重载
    myPrint(d, e);    // 4.函数模板能产生更好的匹配,优先调用模板
}
int main()
{
    test01();
}

1.2.6 模板的局限性

模板不是万能的,有些特定的数据类型,需要用具体化方式做特殊实现
模板的重载,为特定的类型提供具体化的模板

class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
template <class T>
bool myCompare(T &a, T &b)
{
    if (a == b) // 方法1:在Person类中对==符号进行重载
    {
        return true;
    }
    else
    {
        return false;
    }
}

// 方法2:利用具体化的Person版本实现代码,具体化优先调用
template <>
bool myCompare(Person &a, Person &b)
{
    if (a.m_Name == b.m_Name && a.m_Age == b.m_Age) // 方法1:在Person类中对==符号进行重载
    {
        return true;
    }
    else
    {
        return false;
    }
}
void test01()
{
    int a = 10;
    int b = 20;
    bool ret = myCompare(a, b);
    if (ret)
    {
        cout << "a=b" << endl;
    }
    else
    {
        cout << "a!=b" << endl;
    }
}
void test02()
{
    Person p1("Tom", 19);
    Person p2("Tom", 19);
    bool ret = myCompare(p1, p2);
    if (ret)
    {
        cout << "a=b" << endl;
    }
    else
    {
        cout << "a!=b" << endl;
    }
}
int main()
{
    test02();
}

1.3 类模板

1.3.1 类模板语法

类模板作用:
-建立一个通用类,类中的成员 数据类型可以不具体指定,用一个虚拟的类型来代表

template <class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << this->m_Name << endl;
        cout << this->m_Age << endl;
    }
    NameType m_Name;
    AgeType m_Age;
};
void test01()
{
    Person<string, int> p1("孙悟空", 19);
    p1.showPerson();
}
int main()
{
    test01();
}

1.3.2 类模板与函数模板的区别

1.类模板没有自动类型推导的使用方式,必须显式指定类型
2.类模板在模板参数列表中可以有默认参数

template <class NameType, class AgeType = int> // 默认为int类型
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << this->m_Name << endl;
        cout << this->m_Age << endl;
    }
    NameType m_Name;
    AgeType m_Age;
};
// 1.类模板没有自动类型推导
void test01()
{
    // Person p1("孙悟空", 19);报错,不能自动推导类型
    Person<string, int> p1("孙悟空", 19);
    Person<string> p2("猪八戒", 20); // 制定了默认参数类型,因此可以省略int
    p1.showPerson();
    p2.showPerson();
}
int main()
{
    test01();
}

1.3.3 类模板中成员函数创建时机

类模板中成员函数和普通类中成员函数创建时机是有去别的:

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建
class Person0
{
public:
    void showPerson0()
    {
        cout << "show person0" << endl;
    }
};
class Person1
{
public:
    void showPerson1()
    {
        cout << "show person1" << endl;
    }
};
template <class T> // 默认为int类型
class MyClass
{
public:
    T obj;
    // 类模板的成员函数,没有调用的时候不会创建
    void func1()
    {
        obj.showPerson0();
    }
    void func2()
    {
        obj.showPerson1();
    }
};

// 1.类模板没有自动类型推导
void test01()
{
    // 在执行的时候再创建成员函数,判断是否能运行
    MyClass<Person0> m;
    m.func1();
    // m.func2();报错
    MyClass<Person1> m2;
    m2.func2();
}
int main()
{
    test01();
}

1.3.4 类模板对象做函数参数

类模板实例化出的对象,向函数传参的方式

三种传入方式:
1.指定传入类型,最常用
2.参数模板化
3.整个类模板化

查看类型
cout<<typeid(NameYype).name()<<endl;

template <class NameType, class AgeType> // 默认为int类型
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << "Name:\t" << this->m_Name << endl;
        cout << "Age:\t" << this->m_Age << endl;
    }
    NameType m_Name;
    AgeType m_Age;
};
// 1.指定传入类型
void printPerson1(Person<string, int> &p)
{
    p.showPerson();
}
// 2.参数模板发
template <class NameType, class AgeType>
void printPerson2(Person<NameType, AgeType> &p)
{
    p.showPerson();
    cout << "NameType" << typeid(NameType).name() << endl; // 查看type类型
}
// 3.整个类模板化
template <class T>
void printPerson3(T &p)
{
    p.showPerson();
    cout << "NameType:" << typeid(T).name() << endl;
}
void test01()
{
    Person<string, int> p1("sun", 19);
    printPerson1(p1);
    printPerson2(p1);
    printPerson3(p1);
}
int main()
{
    test01();
}

1.3.5 类模板与继承

当类模板碰到继承时,需要注意一下几点:

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定父类中T的类型,子类也需变成类模板
template <class T>
class Base
{
    T m;
};
// class Son : public Base//必须知道父类的T类型,才能继承给子类
class Son : public Base<int>
{
};
// 若想灵活指定类型,子类也需要变类模板
template <class T1, class T2>
class Son2 : public Base<T2> // T2提供给父类,T1提供给子类
{
    T1 n;
};
void test01()
{
    Son s1;
    Son2<int, char> s2;
}
int main()
{
    test01();
}

1.3.6 类模板成员函数类外实现

template <class NameType, class AgeType> // 默认为int类型
class Person
{
public:
    // 类内实现
    // Person(NameType name, AgeType age)
    // {
    //     this->m_Name = name;
    //     this->m_Age = age;
    // }
    // void showPerson()
    // {
    //     cout << "Name:\t" << this->m_Name << endl;
    //     cout << "Age:\t" << this->m_Age << endl;
    // }
    // 类外实现
    Person(NameType name, AgeType age);
    void showPerson();
    NameType m_Name;
    AgeType m_Age;
};
// 构造函数的类外实现
template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) // 1.指定作用域 2.要为模板类指定类型
{
    this->m_Name = name;
    this->m_Age = age;
}
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "Name:\t" << this->m_Name << endl;
    cout << "Age:\t" << this->m_Age << endl;
}
void test01()
{
    Person<string, int> p("tom", 20);
    p.showPerson();
}
int main()
{
    test01();
}

1.3.7 类模板分文件编写

问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到。
解决方法:
方法1:直接包含.cpp源文件
方法2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称,并不是强制

  • 方法1:
    main.cpp
#include <iostream>
#include <string>
#include "person.h"
#include"person.cpp"
using namespace std;
void test01()
{
    Person<string, int> p("tom", 20);
    p.showPerson();
}
int main()
{
    test01();
}

person.h

#pragma once
#include<iostream>
using namespace std;

template <class NameType, class AgeType> // 默认为int类型
class Person
{
public:
    // 类外实现
    Person(NameType name, AgeType age);
    void showPerson();
    NameType m_Name;
    AgeType m_Age;
};

person.cpp

#include "person.h"
template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) // 1.指定作用域 2.要为模板类指定类型
{
    this->m_Name = name;
    this->m_Age = age;
}
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "Name:\t" << this->m_Name << endl;
    cout << "Age:\t" << this->m_Age << endl;
}

-方法2:将.h和.cpp内容写到一起,修改后缀名为.hpp文件
main.cpp同上,person.hpp如下:

#pragma once
#include<iostream>
#include<string>
using namespace std;

template <class NameType, class AgeType> // 默认为int类型
class Person
{
public:
    // 类外实现
    Person(NameType name, AgeType age);
    void showPerson();
    NameType m_Name;
    AgeType m_Age;
};

template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) // 1.指定作用域 2.要为模板类指定类型
{
    this->m_Name = name;
    this->m_Age = age;
}
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "Name:\t" << this->m_Name << endl;
    cout << "Age:\t" << this->m_Age << endl;
}

1.3.8 类模板与友元

掌握类模板配合友元函数的类内和类外实现

全局函数类内实现-直接在类内声明友元即可
全局函数类外实现-需要提前让编译器知道全局函数的存在

// 通过全局函数打印Person信息
// 第2种全局函数的实现方法,需要提前让编译器知道Person类的存在,且将函数放到前面,要让类内知道该代码实现
template <class NameType, class AgeType>
class Person;
template <class NameType, class AgeType>
void showPerson2(Person<NameType, AgeType> p)
{
    cout << "Name:\t" << p.m_Name << endl;
    cout << "Age:\t" << p.m_Age << endl;
}
template <class NameType, class AgeType> // 默认为int类型
class Person
{
    // 1.全局函数在类内实现
    friend void showPerson(Person<NameType, AgeType> &p) // friend 保证可以访问到私有元素
    {
        cout << "Name:\t" << p.m_Name << endl;
        cout << "Age:\t" << p.m_Age << endl;
    }
    // 2.全局函数类外实现
    // 函数模板的声明,需要加一个空参数列表<>,需要让编译器提前知道这个函数
    // template <class NameType, class AgeType>
    friend void showPerson2<>(Person<NameType, AgeType> p);

public:
    // 类内实现
    Person(NameType name, AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

private:
    NameType m_Name;
    AgeType m_Age;
};
void test01()
{
    Person<string, int> p("jerry", 20);
    showPerson(p);
    showPerson2(p);
    // p.showPerson();
}
int main()
{
    test01();
}

1.3.9 类模板案例

实现一个通用的数组类:

  • 可以对内置数据类型以及自定义数据类型的数据进行存储
  • 将数组中的数据存储到堆区
  • 构造函数中可以传入数组的容量
  • 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
  • 提供尾法和尾删法对数组中的数据进行增加和删除
  • 可以通过下标的方式访问数组中的元素。
  • 可以获取数组中当前元素个数和数组的容量
    示例:
    main.cpp
#include <iostream>
#include <string>
#include "MyArray.hpp"
using namespace std;
void printIntArray(MyArray<int> &arr)
{
    for (int i = 0; i < arr.getSize(); i++)
    {
        cout << arr[i] << endl;
    }
}

void test01()
{
    MyArray<int> arr1(5); // 有参构造
    // MyArray<int> arr2(arr1); // 拷贝构造
    // MyArray<int> arr3(100);
    // arr3 = arr1; //=重载
    for (int i = 0; i < 5; i++)
    {
        arr1.Push_Back(i);
    }
    cout << "arr1" << endl;
    printIntArray(arr1);
    cout << "大小:" << arr1.getCapacity() << "容量" << arr1.getSize() << endl;
    arr1.Pop_back();
    cout << "大小:" << arr1.getCapacity() << "容量" << arr1.getSize() << endl;
}
int main()
{
    test01();
}

MyArray.hpp

#pragma once
#include <iostream>
using namespace std;
template <class T>
class MyArray
{
public:
    // 有参构造
    MyArray(int capacity)
    {
        // cout << "有参构造" << endl;
        this->m_Capacity = capacity;
        this->m_Size = 0;
        this->pAddress = new T[this->m_Capacity];
    }
    // 拷贝构造
    MyArray(const MyArray &arr)
    {
        // cout << "拷贝构造" << endl;
        this->m_Capacity = arr.m_Capacity;
        this->m_Size = arr.m_Size;
        // this->pAddress=arr.pAddress;编译器写法,但指针不能这样赋值,出现浅拷贝问题
        // 深拷贝
        this->pAddress = new T[arr.m_Capacity];
        // 将arr中的数据拷贝过来
        for (int i = 0; i < this->m_Size; i++)
        {
            this->pAddress[i] = arr.pAddress[i];
        }
    }
    // operator=防止浅拷贝 a=b=c,返回自身的引用,可以进行连等
    MyArray &operator=(const MyArray &arr) // 这个const是防止误调用
    {
        // cout << "=" << endl;
        if (this->pAddress != NULL) // 首先判断原来的堆区里是否有数据,如果有先释放
        {
            delete[] this->pAddress;
            this->pAddress = NULL;
            this->m_Capacity = 0;
            this->m_Size = 0;
        }
        // 深拷贝
        this->m_Capacity = arr.m_Capacity;
        this->m_Size = arr.m_Size;
        this->pAddress = new T[arr.m_Capacity];
        for (int i = 0; i < this->m_Size; i++)
        {
            this->pAddress[i] = arr.pAddress[i];
        }
        return *this; // 返回自身
    }
    // 尾插法
    void Push_Back(const T &val)
    {
        // 判断容量
        if (this->m_Capacity == this->m_Size)
        {
            return;
        }
        this->pAddress[this->m_Size] = val;
        this->m_Size++;
    }
    // 尾删法
    void Pop_back()
    {
        // 让用户访问不到最后一个元素
        if (this->m_Size == 0)
        {
            return;
        }
        this->m_Size--;
    }
    // 访问第N个元素
    T &operator[](int index) // 若想要返回可以作为左值,需要加引用!!!
    {
        return this->pAddress[index];
    }
    // 返回容量和大小
    int getCapacity()
    {
        return this->m_Capacity;
    }
    int getSize()
    {
        return this->m_Size;
    }
    // 析构函数
    ~MyArray()
    {
        // cout << "析构函数" << endl;
        if (this->pAddress != NULL)
        {
            delete[] this->pAddress;
            this->pAddress = NULL;
        }
    }

private:
    T *pAddress;
    int m_Capacity;
    int m_Size;
};

2.STL初始

2.1STL诞生

  • 可重复利用的东西
  • 面向对象和泛型编程,目的就是复用性提升
  • 为了建立数据结构和算法的标准,诞生了STL

2.2 STL基本概念

  • STL(Standard Template Library,标准模板库)
  • STL分为:容器、算法、迭代器
  • 容器和算法之间通过迭代器无缝衔接
  • STL几乎所有的代码都采用了模板类或者模板函数

2.3 STL六大组件

1.容器:各种数据结构,如vector、list、deque、set、map
2.算法:常用的算法,如sort、find、copy、for_each
3.迭代器:容器和算法的胶合剂
4.仿函数:行为类似函数,可作为算法的某种策略
5.适配器(配接器):修饰容器或者仿函数或迭代器的接口
6.空间配置器:负责空间的配置与管理

2.4 STL中容器、算法、迭代器

容器:将运用最广泛的数据结构实现出来
分类为:

  • 序列式容器:强调值的排序,序列式容器中每个元素均有固定的位置
  • 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

算法:
分类为:

  • 质变算法:运算过程中会更改元素的内容,例如:拷贝、替换、删除
  • 非质变算法:运算过程不会更改元素,例如:查找、计算、遍历、寻找最值等

迭代器:
提供一种方法能够以此访问某个容器所含的各个元素,可以理解为指针

2.5 容器算法迭代器初识

2.5.1 vector存放内置数据类型

容器:vector
算法:for_each
迭代器:vector::iterator

#include <iostream>
#include <string>
using namespace std;
#include <vector>    //容器的头文件
#include <algorithm> //标准算法的头文件
void myPrint(int val)
{
    cout << val << endl;
}
void test01()
{
    // 创建容器
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    // 第一种遍历方式
    // 通过迭代器访问数据
    vector<int>::iterator itBegin = v.begin(); // 指向第一个元素
    vector<int>::iterator itEnd = v.end();     // 指向最后一个元素的下一个位置
    while (itBegin != itEnd)
    {
        cout << *itBegin << endl;
        itBegin++;
    }
    // 第二种遍历方式,第一种的简化
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
    // 第三种遍历方式,利用遍历算法,for_each
    for_each(v.begin(), v.end(), myPrint); // 回调函数,回调函数是参数,但是只能用函数指针调用
}
int main()
{
    test01();
}

2.5.2 vector存放自定义数据类型

#include <iostream>
#include <string>
using namespace std;
#include <vector>    //容器的头文件
#include <algorithm> //标准算法的头文件
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
// 存放自定数据类型
void test01()
{
    vector<Person> v;
    Person p1("aaaa", 1);
    Person p2("bbbb", 2);
    Person p3("cccc", 3);
    Person p4("dddd", 4);
    Person p5("eeee", 5);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << "姓名" << (*it).m_Name << endl;
        cout << "年龄" << (*it).m_Age << endl;
        cout << "name:" << it->m_Name << endl;
        cout << "age:" << it->m_Age << endl;
    }
}
// 存放自定义数据类型的指针
void test02()
{
    vector<Person *> v;
    Person p1("aaaa", 1);
    Person p2("bbbb", 2);
    Person p3("cccc", 3);
    Person p4("dddd", 4);
    Person p5("eeee", 5);
    v.push_back(&p1);
    v.push_back(&p2);
    v.push_back(&p3);
    v.push_back(&p4);
    v.push_back(&p5);
    // 遍历容器
    for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
    {
        // it是一个指针,其指向另一个指针(*it)
        cout << (*it)->m_Name << endl;
        cout << (*it)->m_Age << endl;
    }
}
int main()
{
    test02();
}

2.5.4 vector容器嵌套容器

——类似于二维数组

#include <iostream>
#include <string>
using namespace std;
#include <vector>    //容器的头文件
#include <algorithm> //标准算法的头文件
// 容器嵌套容器
void test01()
{
    vector<vector<int>> v;
    vector<int> v1;
    vector<int> v2;
    vector<int> v3;
    vector<int> v4;
    for (int i = 0; i < 4; i++)
    {
        v1.push_back(i);
        v2.push_back(i + 1);
        v3.push_back(i + 2);
        v4.push_back(i + 3);
    }
    // 将小容器插入大容器
    v.push_back(v1);
    v.push_back(v2);
    v.push_back(v3);
    v.push_back(v4);
    // 遍历大容器
    for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
    {
        // 此时(*it)仍为一个容器
        for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
        {
            cout << *vit << " ";
        }
        cout << endl;
    }
}
int main()
{
    test01();
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值