一、命名空间的using声明
在C++中,命名空间是一种将标识符(如变量、函数、类等)组织到一个单独的作用域中的机制。当我们在大型项目中工作时,可能会遇到命名冲突的问题,这时命名空间就非常有用。
然而,在使用命名空间中的成员时,需要在每个成员前加上命名空间的名字,这可能会使代码变得冗长。为了解决这个问题,C++提供了using
声明和using
指令。
using
声明:它用于从命名空间中引入单个标识符。例如:
namespace MyNamespace {void myFunction() { /* ... */ }
}int main() {using MyNamespace::myFunction; // 使用using声明从MyNamespace中引入myFunctionmyFunction(); // 现在可以直接调用myFunction,不需要加上MyNamespace::return 0;
}
using
指令:它用于从命名空间中引入所有标识符。这通常在头文件中使用,以避免每次使用命名空间中的成员时都必须加上命名空间的名字。但是,如果命名空间很大或包含有命名冲突的标识符,这样做可能会导致问题。
namespace MyNamespace {void myFunction() { /* ... */ }
}int main() {using namespace MyNamespace; // 使用using指令从MyNamespace中引入所有标识符myFunction(); // 现在可以直接调用myFunction,不需要加上MyNamespace::return 0;
}
二、标准库类型string
1定义和初始化string对象
在C++中,std::string
是一个非常强大的字符串处理工具,位于 <string>
标准库中。定义和初始化 std::string
的方式如下:
#include <string>// 默认构造函数
std::string str1;// 基于C风格字符串初始化
const char *cstr = "Hello, World!";
std::string str2(cstr);// 初始化为指定长度和字符
std::string str3(10, 'a'); // "aaaaaaaaaa"// 初始化为另一个string对象的副本
std::string str4(str2);// 初始化为另一个string对象的子串
std::string str5(str2, 7, 5); // "World"
2string对象上的操作
std::string
提供了丰富的操作接口,包括但不限于:
-
连接
1std::string str6 = str1 + str2;
-
比较
1if (str1 == str2) { 2 // 相等 3} else if (str1 < str2) { 4 // str1小于str2 5}
-
查找
1size_t pos = str1.find("world"); // 查找子串位置
-
替换
1str1.replace(pos, 5, "universe");
-
插入
1str1.insert(pos, "extra ");
-
删除
1str1.erase(pos, 5);
-
大小
1size_t len = str1.length();
-
访问元素
1char ch = str1.at(pos); // 或者 str1[pos]
3处理string对象中的字符
std::string str = "Hello";
str[0] = 'h'; // 修改第一个字符为小写
char firstChar = str[0]; // 获取第一个字符使用 at() 方法更安全,因为它会在访问越界时抛出异常:、
try {char ch = str.at(10); // 如果str长度小于10,会抛出std::out_of_range异常
} catch (std::out_of_range& e) {std::cerr << "Error: " << e.what() << std::endl;
}
三、标准库类型vector
std::vector
是 C++ 标准模板库 (STL) 中的一个动态数组容器。它可以自动调整其内部存储空间的大小,以便容纳更多的元素。
1定义和初始化vector对象
#include <vector>
#include <iostream>int main() {// 默认构造,创建空的 vectorstd::vector<int> v1;// 构造并初始化为特定大小和值std::vector<int> v2(10, 1); // 创建一个包含10个元素的vector,每个元素值为1// 构造并初始化为另一个vector的副本std::vector<int> v3(v2);// 构造并初始化为一系列初始值std::vector<int> v4{1, 2, 3, 4, 5};// 构造并初始化为迭代器范围内的元素int arr[] = {1, 2, 3, 4, 5};std::vector<int> v5(arr, arr + sizeof(arr) / sizeof(arr[0]));return 0;
}
2向vector对象中添加元素
std::vector<int> v;// 在向量末尾添加元素
v.push_back(10); // 添加整数10// 使用迭代器在向量末尾添加多个元素
std::vector<int> v2{1, 2, 3};
v.insert(v.end(), v2.begin(), v2.end());// 在指定位置插入元素
v.insert(v.begin(), 0); // 在向量开始处插入0// 使用 emplace_back 和 emplace 在运行时直接在向量中构造对象
std::vector<std::string> vs;
vs.emplace_back("Hello"); // 直接在向量中构造字符串对象
3其他vector操作
std::vector<int> v = {1, 2, 3, 4, 5};// 访问元素
int first = v.front(); // 获取第一个元素
int last = v.back(); // 获取最后一个元素// 删除元素
v.pop_back(); // 删除最后一个元素
v.erase(v.begin()); // 删除第一个元素// 清空向量
v.clear();// 检查是否为空
bool empty = v.empty();// 获取大小和容量
size_t size = v.size();
size_t capacity = v.capacity();// 重新分配大小
v.resize(10); // 将向量大小设置为10
v.resize(5, -1); // 将向量大小设置为5,新位置的元素值为-1// 交换两个向量的内容
std::vector<int> v2 = {6, 7, 8};
v.swap(v2);
四、迭代器介绍
迭代器的工作方式类似于指针,但它们被设计成可以与更广泛的容器一起工作,而不仅仅是原始数组。
1使用迭代器
#include <vector>
#include <iostream>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};// 定义迭代器std::vector<int>::iterator it; // 或简写为 auto it
}// 初始化迭代器指向容器的第一个元素
it = vec.begin();// 初始化迭代器指向容器的最后一个元素后的下一个位置
it = vec.end();// 输出容器中的元素
for (it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";
}for (auto &element : vec) {std::cout << element << " ";
}
2迭代器运算
迭代器支持几种运算,这使得它们在遍历容器和执行操作时更加灵活。
it++; // 移动到下一个元素
it--; // 移动到前一个元素if (it1 == it2) {} // 判断两个迭代器是否指向同一位置
if (it1 != it2) {} // 判断两个迭代器是否不指向同一位置int distance = it2 - it1; // 计算it1和it2之间的距离it = it1 + 5; // 移动迭代器5个位置
it = it1 - 2; // 移动迭代器2个位置
五、数组
1定义和初始化内置数组
// 定义一个整型数组,包含5个元素
int arr[5];// 初始化数组
int arr2[5] = {1, 2, 3, 4, 5}; // 显式初始化所有元素
int arr3[5] = {1, 2, 3}; // 隐式初始化剩余元素为0// C++11 及以后版本的初始化语法
int arr4[] = {1, 2, 3, 4, 5};
int arr5[5] = {0}; // 所有元素初始化为0
2访问数组元素
arr[0] = 10; // 设置第一个元素的值
int val = arr[4]; // 获取第五个元素的值
3指针和数组
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr 现在指向 arr[0]// 通过指针访问元素
std::cout << *ptr << std::endl; // 输出 arr[0]
std::cout << *(ptr + 1) << std::endl; // 输出 arr[1]
4C风格字符串
char str[] = "Hello, World!"; // C风格字符串
std::cout << str << std::endl; // 输出字符串// 访问字符串中的字符
char ch = str[0]; // 获取第一个字符 'H'
5与旧代码的接口
void c_function(char *s) {while (*s) {std::cout << *s++;}
}int main() {char str[] = "Hello from C function";c_function(str); // 调用C风格的函数return 0;
}
现代C++鼓励使用std::array
和std::vector
等更安全、更灵活的容器,因为它们提供了额外的功能并且可以自动管理内存。然而,在某些情况下,使用内置数组和C风格字符串仍然是必要的,尤其是在需要与C库交互或者性能优化要求极高的场景下
六、多维数组
多维数组在内存中是连续存储的,这意味着如果要改变数组的大小,你可能需要重新分配内存,这在C++中通常不是自动的,除非使用std::vector
或std::array
等容器。
C++编译器在编译时会检查数组索引是否越界,但在运行时不会,因此你需要确保你的索引值不会超出数组的界限。
多维数组的内存消耗比一维数组大,因为它们通常用于存储大量数据。在资源有限的环境中,应谨慎使用。