#include <iostream>
// write your code here......
#include <vector>
using namespace std;

int main() {
    
    // write your code here......
    vector<int> vec;
    int a;
    while(cin>>a){
        vec.push_back(a);
    }
    vector<int>::iterator iter=vec.begin();
    for(; iter!=vec.end(); iter++){
        cout<<*iter<<" ";
    }
    cout<<endl;
    for(iter = vec.end()-1 ; iter>=vec.begin(); iter--){
        cout<<*iter<<" ";
    }
    

    return 0;
}

C++ vector 超详细使用教程(零基础必看,最全常用用法+你的实战场景适配)

你之前手写过动态数组 int* a = new int[n],也学了类、多态,vector 就是用来彻底替代原生数组的「超级动态数组」,是C++ STL里最常用、最核心、必须吃透的容器,没有之一。vector 本质就是:C++官方帮你封装好的动态数组类,自动扩容、自动管理内存(不用写new/delete)、自带增删改查,所有原生数组能做的,vector都能做,还能做得更好,更安全。✅ 核心优势:不用手动管理内存、不会内存泄漏、不用写深拷贝、自动扩容,解决你手写数组的所有痛点!

✅ 一、vector 前置必备(写代码前必须加)

1. 必备头文件

所有 vector 的代码,第一行必须引入这个头文件,缺一不可:

#include <vector>

2. 命名空间(可选,但建议加)

不加的话,所有vector要写成std::vector,加了更简洁,你写代码一直加的,直接沿用即可:

using namespace std;

✅ 二、核心语法1:vector的「定义与初始化」(6种常用写法,够用100%场景)

语法格式:vector<存储的数据类型> 容器名;

vector<> 里的内容是泛型/模板参数,指定vector要存什么类型的数据,int/char/string/自定义类/指针都可以!

最常用的6种初始化方式(按优先级排序,越靠前越常用)

#include <iostream>
#include <vector>
using namespace std;

int main() {
    // 写法1:定义空的vector,最常用!先创建空数组,后续再添加元素
    vector<int> v1; 

    // 写法2:定义时直接初始化赋值(推荐,初始化已知数据)
    vector<int> v2 = {1, 2, 3, 4, 5}; 

    // 写法3:定义时指定数组长度,所有元素默认值为0
    vector<int> v3(5);  // v3 = {0,0,0,0,0}

    // 写法4:定义时指定长度 + 指定初始化值
    vector<int> v4(5, 10); // v4 = {10,10,10,10,10}

    // 写法5:用一个vector初始化另一个vector(拷贝)
    vector<int> v5(v2); // v5 = {1,2,3,4,5}

    // 写法6:存储字符串类型(同理,存其他类型只需要改<>里的内容)
    vector<string> v6 = {"hello", "vector", "STL"};
    return 0;
}

✨ 关键提醒

vector<int> 里的 <int> 不能省略!这是模板的语法,告诉编译器这个数组存的是整数,存其他类型就换:

  • 存浮点型:vector<double> v;
  • 存字符型:vector<char> v;
  • 存自定义类对象:vector<Time> v;(比如你之前的Time类)
  • 存指针(多态必备):vector<BaseCalculator*> v;(你的计算器多态)

✅ 三、核心语法2:vector 最常用的「增删改查」操作(重中之重,必会!)

这部分是vector的核心,80%的场景只用到下面这8个操作,全部都是成员函数,用 vector对象名.函数名() 调用,语法和你写的 类对象.成员函数() 完全一致!

所有例子都基于这个基础:vector<int> v = {1,2,3,4,5};

👉 1. 尾部添加元素 【最常用TOP1】push_back(值)

给vector的最后面追加一个元素,vector会自动扩容(满了之后自动变大),不用你手动处理内存,完美替代你手写的数组扩容逻辑!

v.push_back(6); // v变成 {1,2,3,4,5,6}
v.push_back(7); // v变成 {1,2,3,4,5,6,7}

👉 2. 获取数组长度 【最常用TOP2】size()

返回vector里的元素个数,等价于你手写数组时的n遍历数组必用,返回值是整数类型。

cout << v.size() << endl; // 输出5,因为v初始有5个元素
v.push_back(6);
cout << v.size() << endl; // 输出6,添加后长度+1

👉 3. 访问指定下标元素 【最常用TOP3】v[下标]

原生数组的访问方式完全一模一样!下标从0开始,支持读、写两种操作,这是你最熟悉的用法,无缝衔接!

// 读元素:获取下标0的元素
cout << v[0] << endl; // 输出1

// 写元素:修改下标2的元素值
v[2] = 30; // v变成 {1,2,30,4,5}

👉 4. 判断是否为空 empty()

判断vector里有没有元素,为空返回true,不为空返回false,防止遍历空数组报错。

vector<int> v_empty;
if(v_empty.empty()){
    cout << "数组为空" << endl; // 会执行这句
}

👉 5. 清空所有元素 clear()

清空vector里的所有元素,清空后数组长度size()变为0,但不会释放内存(不影响后续使用)。

v.clear(); // v变成空数组
cout << v.size() << endl; // 输出0

👉 6. 尾部删除元素 pop_back()

删除vector最后面的一个元素,删除后长度size()减1。

v.pop_back(); // v变成 {1,2,3,4}

👉 7. 插入元素 insert(位置, 值) (偶尔用)

在指定下标位置插入一个元素,插入后后面的元素自动后移,vector自动扩容。

v.insert(v.begin()+1, 100); // 在下标1的位置插入100,v变成 {1,100,2,3,4,5}

👉 8. 删除元素 erase(位置) (偶尔用)

删除指定下标位置的元素,删除后后面的元素自动前移。

v.erase(v.begin()+2); // 删除下标2的元素,v变成 {1,2,4,5}

✅ 四、核心语法3:vector的「遍历方式」(3种,全部要会!)

遍历 = 把vector里的每个元素都访问一遍,vector有3种遍历方式,全部都要掌握,不同场景用不同方式,适配你的所有需求,全部基于你学过的知识,无缝衔接

所有遍历例子都基于:vector<int> v = {1,2,3,4,5};

✅ 方式1:数组式遍历 【最推荐、最常用】 for(int i=0; i<v.size(); i++)

和原生数组的遍历写法完全一模一样!你手写数组时怎么遍历,vector就怎么遍历,零基础零成本上手,这是你最先要掌握、最常用的方式!

// 遍历输出所有元素
for (int i = 0; i < v.size(); i++) {
    cout << v[i] << " "; // 用v[i]访问元素,和数组一样
}
// 输出:1 2 3 4 5

✅ 优势:语法熟悉、代码简洁、效率最高,90%的场景用这个就够了!

✅ 方式2:迭代器遍历 【STL标准写法】 vector<int>::iterator

迭代器你之前听过,核心记住一句话:迭代器 = vector专属的指针,语法和指针完全一致

  • 定义迭代器:vector<int>::iterator it;int换成你存储的类型)
  • 取元素:*it (和指针*p完全一样)
  • 移动指针:it++ (下一个元素)
  • 开始位置:v.begin() (数组第一个元素的地址)
  • 结束位置:v.end() (数组最后一个元素的下一个地址,结束标志)
// 迭代器遍历
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); it++) {
    cout << *it << " "; // *it 访问迭代器指向的元素,和指针一样
}
// 输出:1 2 3 4 5

✅ 优势:STL标准写法,适配所有STL容器(vector/list/map),学会这个,其他容器的遍历也会了!

✅ 方式3:范围for遍历 【C++11简洁写法】 for(auto x : v)

C++11新增的语法,极简遍历,不用写下标、不用写迭代器,直接遍历所有元素,适合只需要读取元素,不需要下标的场景,代码量最少!

// 范围for遍历,auto自动推导类型为int
for (auto x : v) {
    cout << x << " ";
}
// 输出:1 2 3 4 5

✅ 优势:代码极简,一行搞定遍历,适合快速写代码!

✅ 五、进阶用法1:vector 存储「自定义类对象」(适配你学的类/继承)

你之前写过 rectanglecuboidTimeCalculator 这些自定义类,vector可以直接存储这些类的对象,用法和存储int完全一样,没有任何区别!

例子:存储你之前的矩形类对象

#include <iostream>
#include <vector>
using namespace std;

class rectangle{
private:
    int length,width;
public:
    rectangle(int x=0,int y=0) : length(x), width(y) {}
    int area(){ return length*width; }
};

int main() {
    // 定义存储rectangle对象的vector
    vector<rectangle> rectVec;
    // 添加对象到vector
    rectVec.push_back(rectangle(2,3));
    rectVec.push_back(rectangle(4,5));
    // 遍历调用成员函数
    for(int i=0; i<rectVec.size(); i++){
        cout << rectVec[i].area() << endl; // 输出6、20
    }
    return 0;
}

✅ 六、进阶用法2:vector 存储「指针」实现【多态】(你的核心实战场景,必看!)

这个是对你最有用的用法,完美适配你之前写的「计算器多态代码」!你之前写多态是用 BaseCalculator* cal = new AddCalculator; 手动new/delete,容易忘记释放内存,而用vector存储父类指针,可以统一管理所有子类对象,完美实现多态+自动管理对象,这是C++开发中最标准的多态写法,你必须吃透!

✨ 完整实战代码(你的计算器多态+vector,企业级标准写法)

#include <iostream>
#include <vector>
using namespace std;

// 父类:计算器基类
class BaseCalculator {
public:
    int m_A;
    int m_B;
    virtual int getResult(){ return 0; }
    virtual ~BaseCalculator() {} // 虚析构必须加,防止内存泄漏
};
// 加法子类
class AddCalculator : public BaseCalculator {
public:
    int getResult() override { return m_A + m_B; }
};
// 减法子类
class SubCalculator : public BaseCalculator {
public:
    int getResult() override { return m_A - m_B; }
};

int main() {
    // 核心:定义vector存储【父类指针】
    vector<BaseCalculator*> calVec;

    // 往vector里添加子类对象的地址(多态核心:父类指针指向子类对象)
    calVec.push_back(new AddCalculator);
    calVec.push_back(new SubCalculator);

    // 遍历vector,调用多态函数 → 完美实现多态!
    for(int i=0; i<calVec.size(); i++){
        calVec[i]->m_A = 10;
        calVec[i]->m_B = 5;
        cout << calVec[i]->getResult() << endl; // 输出 15  5
    }

    // 最后统一释放内存(避免内存泄漏)
    for(int i=0; i<calVec.size(); i++){
        delete calVec[i];
    }
    return 0;
}

✅ 这个写法的好处:新增乘法/除法计算器时,只需要加一个子类,然后calVec.push_back(new MulCalculator)即可,原有代码一行不改,完美体现多态的扩展性!

✅ 七、vector 对比 原生动态数组(为什么vector香?)

你之前手写的动态数组:int* a = new int[n];,对比vector,vector的优势是碾压级的,这也是为什么一定要用vector的原因:

内存管理

手动写

new/delete

,容易泄漏/崩溃

自动管理,无需手动操作

扩容

手动重新分配内存+拷贝数据,超麻烦

自动扩容,

push_back

直接加元素

深拷贝

必须自己写深拷贝构造,容易出错

自带深拷贝,赋值/拷贝都安全

越界检查

无,越界直接崩溃

有间接保护,更安全

代码量

多,需要写构造/析构/深拷贝

极少,一行定义,直接用

✨ 结论:以后再也不要手写动态数组了,所有数组场景都用vector替代!

✅ 八、易错点提醒(新手必避坑)

  1. 下标越界:vector的下标从0开始,最大下标是v.size()-1,如果访问v[v.size()]会直接崩溃,和数组一样;
  2. 空vector访问元素:如果v.empty()为true,还访问v[0]会崩溃;
  3. 存储指针时记得释放内存:比如存储多态指针的vector,最后一定要遍历delete,否则内存泄漏;
  4. vector的size()返回值是无符号整数:不要写for(int i=v.size()-1; i>=0; i--),会出现死循环,用int len = v.size();先存起来即可。

✅ 九、vector 常用操作速查表(收藏备查,不用记,看表就行)

vector<int> v;          // 定义空vector
v.push_back(x);         // 尾部加元素
v.size();               // 获取长度
v[i];                   // 访问下标i的元素
v.empty();              // 判断是否为空
v.clear();              // 清空所有元素
v.pop_back();           // 尾部删元素
v.insert(v.begin()+i,x);// 下标i插入x
v.erase(v.begin()+i);   // 删除下标i的元素

✅ 总结(核心知识点,一句话记死)

  1. vector 是「动态数组」,完全替代原生数组,自动管理内存、自动扩容、无需new/delete
  2. 核心语法:vector<类型> 名 定义,push_back加元素,size()取长度,v[i]访问元素;
  3. 遍历方式:数组式遍历(最常用)、迭代器遍历(标准)、范围for(简洁);
  4. 高阶用法:存储自定义类对象、存储父类指针实现多态(你的核心场景);
  5. 记住:以后写C++,所有需要数组的地方,无脑用vector就对了!

你现在的基础(类、指针、多态)已经完全能吃透vector了,vector是你STL的入门第一课,学会它之后,你会发现C++编程的效率直接翻倍,再也不用被内存管理的问题困扰了!🎉