C++知识框架
简介
起源:贝尔实验室20世纪80年代。C也是贝尔实验室的研究员丹尼斯·里奇。
应用范围:操作系统、编译器、文字处理程序、大型游戏。
C++ vs C:C是结构化和模块化的语言。C++增加了面向对象的机制(俗称"带类的C")。
语法
数据类型
//x64处理器 64位window10 vs2015
#include <iostream>
using namespace std; // 没有此,则cout 时,需要写成 std::cout
int main()
{
/*
cout:字符输出流对象
<< 是输出运算符
endl 是用于输出换行并刷新缓冲区
*/
cout << sizeof(bool) << endl;
cout << sizeof(char)<<" " << sizeof(short)<<" "<< sizeof(signed int) << " " << sizeof(long) << " " << sizeof(signed long long) << " " << sizeof(float) << " " << sizeof(double) << " " << sizeof(float) << " " << sizeof(long double) << endl;
cout <<sizeof(unsigned char)<<" "<< sizeof(unsigned short) << " " << sizeof(unsigned int) << " " << sizeof(unsigned long) << " " << sizeof(unsigned long long) << endl;
cout << sizeof(unsigned) << endl;
system("pause");
return 0;
}
// 输出
1
1 2 4 4 8 4 8 4 16
1 2 4 4 8
4
typedef声明:
typedef int myint; // 后面直接可以使用myint num = 123;
枚举
enum course {
chinese,
math,
english
};
int main()
{
course c = math;
cout << c << endl; // 输出:1
return 0;
}
结构体
// Demo1: struct定义结构体
struct person
{
int year;
int age;
string name;
}p1 = {2024, 24, "adair"}, p2 = {2025, 25, "adair2"};
int main()
{
struct person p3 = {2026, 26, "adair3"};
cout << p1.name << endl;
cout << p3.name << endl;
}
// Demo1: 结构体数组
struct person
{
int year;
int age;
string name;
}p[2] ={ {2024, 24, "adair"}, {2025, 25, "adair2"}};//可以不指定数组元素个数
p[1].age;
结构体对齐
// 默认指定对齐值=8
struct st1
{
// 空结构体大小1
char c1;//1
char c2;//2
int i1;//8 由于出现int(4个字节),下面都是4的整数
char c3;//12
short s4;//12
double d;//24 由于出现double(8个字节),下面都是8的整数
char c4;//32
int i2;//32 28+4 = 32
int i3;//40
short s5;//40
};
//指定对齐值=4
#pragma pack(4)
struct st2
{
//1 空结构体大小1
char c1;//1
char c2;//2
int i1;//8
char c3;//12
short s4;//12
double d;//20
char c4;//24
int i2;//28
int i3;//32
short s5;//36
};
int main()
{
cout << sizeof(st1) << endl;//40
cout << sizeof(st2) << endl;//36
}
共用体
union data {
char c;
int i;
float f;
}x = {.f = 1.1234}; // 初始化
int main()
{
data y = {'A'}; // 初始化
cout << x.f << endl;
// 存储是二进制相同,区别就是如何解释。
cout << y.i << endl;
cout << y.c << endl;
cout << y.f << endl;
}
变量
// 变量声明
extern int a, b;
int main ()
{
// 变量定义
int a, b;
// 初始化
a = 23;
b = 25;
return 0;
}
变量的作用域
// demo1: 局部变量和全局变量相同,函数内使用局部的值。
int i = 66;
int main ()
{
int i = 88;
cout << i << endl;// 88
cout << ::i << endl; // 66
return 0;
}
// demo2: 全局变量为初始化时,int/float/double自动为0, char为'\0',指针为NULL
int i;
float f;
double d;
char c; // c默认为'\0'所以不会输出
int *p;
int main()
{
cout << i << f << d << "c=" << c << "p=" << p << endl;//000c=p=0
return 0;
}
运算符
int d = ~234; // d = -235。~n=-n-1
// 赋值运算符:+= -= *= /= %= <<= >>= &= ^= !=
数组
int array[5]= {2, 3, 4, 5, 6}; // array常量指针
,auto 类型也是 C++11 新标准中的,用来自动获取变量的类型
// 遍历
for(auto x : array){ // int 也可以改为 auto
cout << x << endl;
}
cout << *(array+2) << endl; // 输出:4
cout << sizeof(array) / sizeof(array[0]) << endl; // 总个数
cout << end(array) - begin(array) << endl; // 同上
/* 如果直接打印end(array)和begin(array) ,则差值为 个数*sizeof(type_t)*/
int arr1[4] = {1,2,3,4};
int arr2[4] = { 1,2 }; // 等效于1,2,0,0
int arr[4] = {0};//所有元素为0
二维数组
// Demo1: 数组和地址
int arr1[2][3];
int arr[2][3] = {0};//所有元素为0
int arr2[2][3] = { {1,2,3},{4,5,6} };
int arr3[2][3] = { 1,2,3 ,4,5,6 };
int arr4[2][3] = { {1},{4,6} };
int arr5[][3] = { 1,2,3 ,4,5,6 };
// 获取行数和列数和总个数
int rows = sizeof(arr) / sizeof(arr[0]);
int cols = sizeof(arr[0]) / sizeof(arr[0][0]);
int sum = sizeof(arr) / sizeof(arr[0][0]);
// 获取指向数组首元素的指针
int* ptr = (int*)arr2;
cout << "arr2[0][0] = " << *ptr << endl; // 等效于 **arr2
cout << "arr2[0][1] = " << *(ptr + 1) << endl; // 等效于 *(*arr2 + 1)即arr+n*sizeof(type_t)。
cout << "arr2[1][0] = " << *(ptr + 3) << endl; // 等效于 *(*arr2 + 3)
cout << "arr2 = " << *(*arr2 + 1) << endl; // 输出:2
cout << "arr2 = " << **(arr2+1) << endl; // 输出:4
/* 二维数组:
*arr表示第一行数组指针arr[0]
*(arr+1)表示第二行数组指针arr[1]
*(*(arr+i)+j) 表示a[i][j]。等效*(arr[i] + j)
*(*arr+n) 表示arr数组的第n+1个值
arr[i] == &arr[i][0]
一维数组:
int *p1 = arr; // 等效 &arr[0];
cout << *p1 << endl;
*/
// Demo2: 二维数组指针赋值
int a[2][3] = { {1,2,3},{4,5,6} };
int (*ap)[3];
ap = a;
cout << *(*(ap+1)+1) << endl;
// 二维数组遍历,双层for
数组和new(动态创建数组)
int* arr1 = new int[2]; //delete []arr1;
int* arr2 = new int[2] {1, 2};
// demo1: new创建二维数组
int rows = 3, cols = 2;
int** arr = new int*[rows];
for (size_t i = 0; i < rows; i++)
{
arr[i] = new int[cols]
}
// 依次赋值即可...
arr3[0][1] = 1;
// 释放内存
for (int i = 0; i < m; ++i) {
delete[] arr[i]; // 释放每行的内存
}
delete[] arr; // 释放指针数组
// demo2: 一维数组模拟二维数组
int* arr4 = new int[2 * 3];
// 依次赋值即可...
arr4[0] = 1; // arr4[i * n + j] 可以遍历
// 释放内存
delete[] arr4; // 释放整个一维数组
数组与函数:
如果传递二维数组,形参必须制定第二维的长度。
条件编译
#ifdef Identifier // 亦可#ifndef Identifier
program1
#else
program2
#endif
#if express // express为true则执行program1
program1
#else
program2
#endif
指针
// 指针和二维数组:在前面说过。
// Demo1: 指针和函数
#include <iostream>
int* getLocalVariable() {
int localVar = 42; // 普通局部变量
return &localVar; // 返回局部变量的地址,这是不安全的,会
}
int main() {
int* ptr = getLocalVariable(); // 这里会出错
std::cout << *ptr << std::endl; // 访问野指针(悬空指针),未定义行为
return 0;
}
// 解决方法:static int localVar = 42;
// Demo2: p+n(指针运算)得到的地址是p+n*sizeof(type_t)。
int arr[5] = {1, 2, 3, 4, 5};
int *p1 = &arr[1];
int *p2 = &arr[3];
cout << p2 - p1 << endl; // 输出:2。可以反知:p2 = p1 + 2;
// Demo3: new 和 delete
int* p = new int(2); // 赋值
cout << *p << endl;
delete p;
int* arrp = new int[10];
for (size_t i = 0; i < 10; i++) {
arrp[i] = i;
}
cout << arrp[7] << endl;
delete[] arrp; //释放为多个变量分配的地址
引用&
// Demo1: 变量引用
int a = 10;
int &b = a; //a和b表示相同的变量,具有相同的地址。
// Demo2: 函数引用。可以修改实参。
int add1(int &r) {
r += 1;
return r;
}
// 错误:返回的是局部变量
int add1(int &r) {
r += 1;
int res = r;
return res;
}
无论什么指针,最后都要delete释放内存。
函数
// Demo1: 使用函数,修改传递过来的实参
int add(int& value){ // 使用&(引用)、*(地址)可以改变传过来的v。直接使用v则不改变。
return ++value;
}
int main ()
{
int v = 1;
cout << add(v) << endl;
cout << v << endl;
return 0;
}
// Demo2: 参数默认值
int add(int value, int count = 2){
return value + count;
}
int main ()
{
int v = 1;
cout << add(v) << endl;
return 0;
}
// Demo3: 函数指针
void add1(int &x) {
x += 1;
}
int main()
{
int num = 2;
void (*funcPtr)(int &) = &add1;
funcPtr(num);
cout << num << endl; // 输出:3
}
函数重载
// 均为重载函数
int add(int a,int b)
{
return a+b;
}
int add(int a,int b,int c)
{
return a+b+c;
}
double add(double a,double b)
{
return a+b;
}
// 反例(不是重载函数)。只有返回类型不同,则不是重载函数
double add(int a,int b)
{
return a+b;
}
内联函数
用内联函数替换,所以不发生函数调用,不需要保护现场,恢复现场,节省了开销。
// 可以使用汇编看add()是否发生call,如果有call则说明inline模式不成功
inline int add(int a, int b) {
return a + b;
}
int main ()
{
cout << add(1, 4) << endl;
return 0;
}
// 如果内联函数过于复杂(比如双层for循环),编译器就把内联函数当做普通函数看待了
字符串
C的格式:
// C的字符串就是字符数组,最后一位是'\0'。
char str[7] = {'h','e','i','r','e','e','\0'};
// 也可以使用 双引号代替数组
char str2[] = "abc";
// 使用指针代替,
char* strptr = "abc";
cout << str << endl;
cin >> str; // 修改str的值
cout << str << endl;
// 常用函数
strcat(char s1[],const char s2[]);//将s2接到s1上
strcpy(char s1[],const char s2[]);//将s2复制到s1上
strcmp(const char s1[],const char s2[]);//比较s1,s2 s1>s2返回1 相等返回1,否则返回-1
strlen(char s[]);//计算字符串s的长度 字符串s的实际长度,不包括\0在内
C++格式
// 使用string对象
string str = "Shanghai" ;
cout << str << endl;
str[5] = 'H'; // 修改某位字符
cout << str << endl;
// 字符串数组
string arr[3] = {"abc", "xyz", "123"};
cout << arr[0] << endl;
// 常用函数
string str = "Shanghai" ;
cout << str.size() << endl;
str.insert(5,"Hello"); // 插入
str.append("aaa"); // 追加
str += "bbb"; // 追加
// str.erase(1,3);
str.replace(3, 2 ,"bbb");
cout << str.find("bbb") << endl; // 反向查找 str.rfind()
cout << str.find_first_of("aeiou") << endl; // 查找第一个元音字母
cout << str << endl;
// 字符串遍历1: str.size() for循环下标
// 字符串遍历2: 正向迭代器
for (string::iterator iter = str.begin(); iter < str.end(); iter++)
{
cout << *iter;
}
cout << endl;
// 字符串遍历3: 反向迭代器
for (string::reverse_iterator riter = str.rbegin(); riter < str.rend(); riter++)
{
cout << *riter;
}
字符串分割:
char str[] = "I,am,a,student; hello world!";
const char *split = ",; !";
char *p2 = strtok(str, split);
while (p2 != NULL)
{
cout << p2 << endl;
p2 = strtok(NULL, split); // 继续分割
}
字符串之间的区别
// C 和 C++ 在此都是一样的
// str 数组会被分配在栈上,并且包含所有的字符,包括字符串的结束符 \0。可以修改数组中的字符。
char str[] = "I,am,a,student; hello world!";
str[0] = 'i'; // 可以修改
// 字符串常量存储在 只读内存区。不可以修改字符串
char* str = "I,am,a,student; hello world!";
// 如果const char* str:更加表明不可修改。
域运算符
// Demo1: 访问类的静态成员函数、静态变量
class MyClass {
public:
static int staticVar;
static void staticFunction() {
cout << "This is staticFunction" << endl;
}
};
// 静态成员变量需要使用双冒号访问
int MyClass::staticVar = 10;
int main() {
// 通过类名和作用域解析运算符访问静态成员
cout << MyClass::staticVar << endl;
MyClass::staticFunction();
return 0;
}
// Demo2: 访问命名空间中的函数、类、变量等成员。
// 定义命名空间
namespace MyClass {
int var = 10;
void func() {
cout << "This is func" << endl;
}
};
int main() {
// 访问命名空间中的成员
cout << MyClass::var << endl;
MyClass::func();
return 0;
}
// Demo3: 访问全局变量
int var = 1;
int main() {
int var = 2;
cout << ::var << endl;
return 0;
}
// Demo4: 类外定义函数
class MyClass {
public:
void display();
};
// 类外定义成员函数时使用双冒号
void MyClass::display() {
cout << "This is display" << endl;
}
int main() {
MyClass obj;
obj.display();
return 0;
}
// Demo5: 访问嵌套类
class Outer {
public:
class Inner {
public:
void display(){
cout << "Outer -> Inner -> dispaly()" << endl;
}
};
};
int main() {
Outer::Inner obj;
obj.display(); // 通过作用域解析访问嵌套类
return 0;
}
类
类也是一种数据类型。
// 类的声明
class 类名
{
public: // 权限:类外均可访问
公有数据成员;
公有成员函数;
private: // 权限:只有类内进行访问
私有数据成员;
私有成员函数;
protected: // 权限:类内和派生类可以访问
保护数据成员;
保护成员函数;
};
// 成员函数的定义
返回类型 类名:成员函数名(参数列表) // 类外定义
{
函数体;
}
inline 返回类型 类名:成员函数名(参数列表) // 类外定义(内联函数)
{
函数体;
}
类的实例化
class Person {
public:
int age;
string name;
// 构造器
Person(int age, string name) : age(age), name(name){
}
// 空构造器。如果没有构造器,默认会有一个空构造器
Person(){}
};
int main()
{
Person* p1 = new Person(10, "Alice"); // 使用指针
Person p2(11, "Bob"); // 使用构造器
Person p3; // 使用空构造器
p3.age = 12;
p3.name = "Tom";
cout << p1->age << endl;
cout << p2.name << endl;
cout << p3.name << endl;
cout << p4->name << endl;
}
类的函数实现
class Person {
public:
// 默认参数
Person(int = 0, string = "zhangsan");
Person(Person& p); // 拷贝构造函数
void show();
private:
int age;
string name;
};
Person::Person(int i, string str){
age = i;
name = str;
}
Person::Person(Person& p) {
age = p.age;
name = p.name;
}
void Person::show(){
cout << "age = " << age << ",name =" << name << endl;
}
int main()
{
Person p1;
Person p2(12);
Person p3(13, "lisi");
Person p4(p3);
p1.show();
p2.show();
p3.show();
p4.show();
return 0;
}
析构函数
#include <iostream>
using namespace std;
class Person {
public:
/* 如果去掉const报错:
字符串字面量(例如 "adair")本质上是常量字符数组,为 const char[] 类型
如果绑定到一个非常量的引用类型(如 string&),破坏常量数据的不可修改性。
使用 const string& 是OK,因为编译器保证你不会修改引用的内容。
*/
Person(const string& name){
this->name = new string(name);
cout << "Construct..." << endl;
}
// 析构函数: 函数名 = 类名,无参无返回
~Person(){
delete name;
cout << "Destroyed..." << endl;
}
// const表示不会修改对象的任何成员变量(mutable 除外)
void show() const{
cout << "name = " << *name << endl;
}
private:
string* name;
};
int main()
{
Person p("adair");
p.show();
return 0;
}
函数指针
Person p("adair");
void (Person::*pfun)() = &Person::show;
(p.*pfun)(); // 等效,p.show();
类中还有this指针
// 在类的定义中
this->age;
静态成员
class MyClass {
static int count;
static void show() {
cout << count << endl;
}
}
int main() {
MyClass::count = 1;
MyClass::show();
MyClass obj;
obj
}
友元函数
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val){}
// 友元函数
friend void show(const MyClass& obj);
};
void show(const MyClass& obj) {
// 可以访问类的private
cout << obj.data << endl;
}
int main() {
MyClass obj(3);
show(obj);
return 0;
}
类和结构体:
- C++引入结构体,是为了兼容C。C中空结构体sizeof(type_t)为0,而C++空结构体为1.
- C++结构体中可以定义函数
- C++结构体默认public,类中默认private
struct Person {
int age;
string name;
void show() {
cout << age << endl;
}
};
int main() {
// 如果Person改为class,则不可以访问。
struct Person p;
p.age = 2;
p.name = "adair";
p.show();
}
继承
继承方式 / 基类成员 | public成员 | protected成员 | private成员 |
---|---|---|---|
public | publice | protected | 不可见 |
protected | protected | protected | 不可见 |
private | private | private | 不可见 |
子类修改基类的范围
class Base{
public:
void show(){};
protected:
int a;
int b;
};
class Person:public Base {
public:
using Base::a; // 让base类的protected变成public
using Base::b;
private:
using Base::show;
string name;
};
int main() {
Person *p = new Person();
p->a = 1; // 如果没有修改范围,报错
p->b = 2;
// show()不可以访问
delete p;
return 0;
}
// Demo2: 派生类 转为 基类
class A {
public:
int a;
};
class B : public A {
public:
int b;
};
int main() {
B *b;
b->a = 1;
b->b = 2;
A* a = (A*)b; // 无论是指针还是对象,都会损失变量b.b.
return 0;
}
继承中构造器和析构函数。
class Base{
private:
int a;
int b;
public:
Base(int, int);
~Base();
};
Base::Base(int val1, int val2) : a(val1) , b(val2){
cout << "Base constructor..." << endl;
}
Base::~Base(){
cout << "Base destroy..." << endl;
}
class Person : public Base {
public:
Person(int, int, string);
~Person();
private:
string name;
}; // 类后面要带`;`
Person::Person(int a, int b, string str) : Base(a, b), name(str){
cout << "Person constructor..." << endl;
}
Person::~Person(){
cout << "Person destroy..." << endl;
}
int main() {
cout << "Create..." << endl;
Person *p = new Person(1, 2, "adair");
cout << "Delete..." << endl;
delete p;
return 0;
}
// 输出
Create...
Base constructor...
Person constructor...
Delete...
Person destroy...
Base destroy...
多继承
// Demo1: 基本多继承
class A {
public:
void eat(){
}
};
class B {
public:
void sleep(){
}
};
class C : public A, public B {
public:
void run(){
}
};
int main() {
C c;
// 均为正确调用
c.eat();
c.sleep();
c.run();
return 0;
}
// Demo2: 两个基类有同样的方法
class A {
public:
void sleep(){
}
};
class B {
public:
void sleep(){
}
};
class C : public A, public B {
public:
void run(){
// 解决歧义问题:如果c.sleep()则会报错,因此直接使用run()代替
A::sleep();
B::sleep();
}
};
// Demo3: 虚基类
class A {
public:
int a;
};
class B : virtual public A {
public:
int b;
};
class C : virtual public A {
public:
int c;
};
class D : public B, public C {
public:
int d;
};
int main() {
D d;
// 均为正确调用
d.a = 1;
d.b = 1;
d.c = 1;
d.d = 1;
return 0;
}
/*
如果B类中再声明int a;则d.a访问的就是B中的a;
如果B类和C类同时再次定义a,则歧义。
*/
虚函数
// Demo1: 虚函数
class A {
public:
virtual void show(){
cout << "A show" << endl;
}
};
class B : public A {
public:
void show(){
cout << "B show" << endl;
}
};
int main() {
B b;
b.show(); // B show
A* a = &b;
a->show(); // B show,如果没有virtual,则为A show
A aa = (A)b;
aa.show(); // A show
return 0;
}
// Demo2: 纯虚函数。
class A // A中的方法就相当于接口
{
public:
virtual void show() = 0;
};
class B: public A
{
public:
void show()
{
cout << "B show" << endl;
}
};
重载
// Demo1: 减号重载
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
Point operator+ (const Point& p){ // 重载 -、*、/、自增、自减...
return Point(x + p.x, y + p.y);
}
void show() {
cout << "x = " << x << ", y = " << y << endl;
}
Point operator++(){
(this->x)++;
(this->y)++;
return *this;
}
};
int main(){
Point p1(1, 2);
Point p2(3, 4);
Point p3 = p1 + p2;
// 等效p1.operator+(p2).show();
p3.show();
// 等效p1.operator++().show();
(++p1).show();
return 0;
}
// Demo2: 自增/自减:前置 or 后置
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
// 前置自增
Point& operator++(){ // 返回的是引用,因为需要修改值
x++;
y++;
return *this;
}
// 后置自增
Point operator++(int){ // 返回的是对象,因为无需要修改值
Point temp = *this;
++(*this); // 调用前置自增
return temp;
}
void print() const {
cout << "x = " << x << ",y = " << y << endl;
}
};
int main(){
Point p1(1, 2);
p1.print(); // 1, 2
p1++;
p1.print(); // 2, 3
Point p2 = p1++;
p2.print(); // 2, 3
p1.print(); // 3, 4
return 0;
}
// Demo3: 字符串重载
class String {
public:
string str;
/* const string& str 优于 const string str
const string str:会进行拷贝副本,为局部变量。
const string& str:不拷贝,直接用指针,高效,const又表明不会修改其值
*/
String(const string& str) : str(str) {}
// 赋值运算符重载
String& operator=(const String &s);
};
String& String::operator=(const String &s)
{
if (this != &s) { // 防止自我赋值
str = s.str; // 直接使用 string 类的赋值运算符
}
return *this;
}
int main() {
String s1("hello"); // 使用 string 直接构造
String s2("123");
s2 = s1; // 使用赋值运算符
cout << s2.str << endl; // 输出 hello
string s3;
return 0;
}
// Demo4: 类型转化
class A {
private:
int x, y;
public:
A(int x, int y) : x(x), y(y) {}
operator int(){
return x + y;
}
};
int main() {
A a(3, 4);
int num = a;
cout << num << endl; // 7
return 0;
}
IO流(IOS)
输入流、输出流都是对于内存来说的。内存缓冲区用来存放流的数据。
分类:
- iostream:istream,ostream,iostream
- fstream:ifstream,ofstream,fstream
- strstream:istrstream,ostrstream,strstream
tip:
- cin 就是该类istream的对象。cout 就是该类ostream的对象。
- cerr 不使用缓冲区,直接向显示器输出信息;而输出到 clog 中的信息会先被存放到缓冲区,缓冲区满或者刷新时才输出到屏幕。
// Demo1: 循环读取键盘值
char c; // 通过c = cin.get();读取键盘上的一个字符
while ((c = cin.get()) != EOF) // 等效 while (cin.get(c)){
{
// 如果不判断,换行符也会打印
if (c != '\n') {
cout << c << endl;
}
}
// Demo2: 读取字符串
char arr[5];
cin.get(arr, 5, '\n'); // 最多四个字符,最后一个存'\0'
库
标准库STL
也就是使用using namespace std;
IO库:
- iostream:标准输入输出流cin、cout、clog、cerr
- fstream:文件输入输出流ifstream、ofstream、fstream
- sstream:字符串流istringstream、ostringstream、stringstream
- cstdio: 与C 风格的输入输出函数printf、scanf
- cstdlib:与C 标准库相关的实用函数exit、system、atoi
- 内存管理malloc(size_t sizie)、free(void* ptr)
- 程序控制exit(int status)、system(const char* command)、abort()
- 数学:rand()、srand(unsigned int seed)、abs(int n)、div(numer, denom);
- 转换函数:atoi(const char* str)、atof(const char* str) 、strtol(const char* str, char** endptr, int base)
容器库:
- vector:动态数组,允许按索引访问元素。
- list:双向链表,高效增删
- deque:双端队列,两端增删
- set:集合,自动排序不重复。
- map:映射,键值对存储。自动排序
- unordered_set:同上,没有顺序,查找更高效
- unordered_map:同上,没有顺序,查找更高效
- stack:栈,后进先出(LIFO)
- queue:队列,先进先出(FIFO)
- priority_queue:按优先级访问队列元素
算法库:
- algorithm:提供常用算法,比如sort、find、reverse、
- functional:提供函数对象、函数指针等功能std::bind、std::function、std::mem_fn 等。
- numeric:提供数值算法,如累加、乘积、最大最小值等(例如 accumulate、inner_product)。
字符串库:
- string: C++ 字符串类 std::string,支持动态字符串操作。
- cstring:C 风格的字符串操作,类似于 C 语言中的 <string.h>,提供如 strlen、strcpy、strcmp 等函数。
数学库:
- cmath:提供数学函数,如三角函数、指数函数、对数函数等(例如 sin、cos、log、sqrt)。
- cstdlib:说过rand()
- complex:复数
- valarray:支持数学运算数组,高效
时间:
- ctime:C 风格的时间函数,支持获取当前时间、格式化输出等功能
- chrono:可以进行精确的时间测量、延时等操作。
线程和并发库:
- thread:创建和管理线程
- mutex:提供互斥锁,用于线程同步
- atomic:提供原子操作,支持无锁编程
- condition_variable:提供条件变量,用于线程间的协调
类型支持库:
- type_traits:提供类型相关的工具,如检查类型、判断类型特性、类型转换等。
- memory:提供智能指针(如 std::unique_ptr、std::shared_ptr)和内存管理功能。
- utility:提供实用的工具函数,如 std::swap、std::move、std::pair 等。
异常处理库:
- exception:提供 C++ 异常处理的基础类,如 std::exception。
- stdexcept:提供标准的异常类,如 std::out_of_range、std::invalid_argument 等。
输入输出(文件系统):
- filesystem:提供文件和目录操作的支持(如创建、删除、重命名文件、遍历目录等)。
其他库:
- initializer_list:初始化列表的支持,允许在构造时使用花括号初始化对象。
- bitset:提供位集操作
- random:提供随机数
- locale:提供区域设置和文化特性相关的功能
其他
long的数据类型长度:
已知:操作系统字长和机器字长未必一致(比如某些操作系统可能在 64 位的机器上运行),编译器根据操作系统字长来定义int字长。
在32位操作系统中,long为32位。在64位操作系统中,long在Linux上为64位,在Windows中则为32位,这是因为 Windows 的 64 位 ABI(应用程序二进制接口)并未改变 long 类型的大小。
VS code
配置C++步骤
- 安装好 gcc、g++ 和 gdb 等工具。
- VS Code 中安装 C/C++ 扩展
- 资源管理器中创建一个文件夹,并用vs code打开。
- 然后就可以新建文件demo.cpp然后选择编译器直接运行或调试。
查看C++对应汇编:
// 在调试控制台输入
-exec disassemble /m
问题
inline
友元函数的AB类访问问题