C++语言常见知识点
C++基础#
变量存在的意义是什么?#
作用:给一段指定的内存空间起名,方便我们管理操作这块内存。
int a=10;
常量的两种定义方式#
1、#define PI 3.14 2、const int a=10;
用于记录程序中不可更改的数据。
标识符的命名规则#
1、不能是关键字
2、只能由字母、下划线、数字构成
3、不能数字开头
4、区分大小写
为什么要有数据类型?#
C++规定在一个变量或者常量时,必须要指出相应的数据类型,否则无法给变量分配内存。
存在的意义:给变量分配合适的内存空间,不要造成浪费。
sizeof关键字有什么用?#
利用sizeof关键字可以统计数据类型所占用内存大小(字节大小)。
sizeof( 数据类型/变量 )
科学计数法表示#
float f=3e2;// 3* (10^2)
float f2=3e-2;// 3* (0.1^2)
C++中的字符变量#
char a='a';
- C/C++中字符型变量只占用1个字节。
- 字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII码放入到存储单元。
- cout<<(int)a<<endl; a=>97;A=>65
转义字符:用于表示一些不能显示出来的ASCII字符。 \n \ \t
C++生成随机数#
int num = rand() % 100; // 0~99
goto语句#
不推荐用,知道就好。
cout << "a" << endl; cout << "b" << endl; goto FLAG; cout << "c" << endl; FLAG: cout << "d" << endl; /* a b d */
数组#
所谓数组,就是一个集合,里面存放了相同类型的数据元素。
特点:1、每个数据元素都是相同的数据类型2、数组由连续的内存地址组成
一维数组名的用途#
int arr[5]={1,2,3,4,5};
1、可以统计整个数组在内存中的长度
sizeof(arr)、sizeof(arr[0])
2、获取数组在内存中的首地址。
cout<<arr<<endl;
cout<<&arr[0]<<endl; // 获取数组中第一个元素地址。与数组首地址一样
二维数组名的用途#
int arr[2] [3]={{1,2,3},{4,5,6}};
1、可以统计整个数组在内存中的长度
sizeof(arr)、sizeof(arr[0]) 第一行所占用的内存空间大小、sizeof(arr[0] [0]) 第一个元素所占内存空间大小
sizeof(arr)/sizeof(arr[0]) 获取行数、sizeof(arr[0])/sizeof(arr[0] [0]) 获取列数
2、获取数组在内存中的首地址。
cout<<arr<<endl;
cout<<arr[0]<<endl; 获取第一行数据首地址
cout<<arr[1]<<endl;
函数有什么用?#
作用:将一段经常使用的代码封装起来,减少重复代码。
一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
什么是函数值传递?#
所谓值传递,就是函数调用时实参将数传入给形参。
值传递时,如果形参发生改变,并不影响实参。
void swap(int a, int b) { cout << "2:a= " << a << endl; cout << "2:b= " << b << endl; int temp = a; a = b; b = temp; cout << "2:a= " << a << endl; cout << "2:b= " << b << endl; } int main() { int a = 10; int b = 20; cout << "1:a= " << a << endl; cout << "1:b= " << b << endl; swap(a, b); cout << "1:a= " << a << endl; cout << "1:b= " << b << endl; system("pause"); return 0; } /* 1:a= 10 1:b= 20 2:a= 10 2:b= 20 2:a= 20 2:b= 10 1:a= 10 1:b= 20 */
指针有什么用?#
作用:可以通过指针间接访问内存。
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量来保存地址
int a = 10; int* p = &a;// 让指针p记录a的地址 cout << "a= " << a << endl; cout << "*p= " << *p << endl;// 解引用 cout << "&a= " << &a << endl;// &取地址 cout << "p= " << p << endl; /* a= 10 *p= 10 &a= 000000A2FEEFF5C4 p= 000000A2FEEFF5C4 */
指针这种数据类型所占用的内存空间有多大呢?#
sizeof(int *)
32位操作系统,占用4个字节
64位操作系统,占用8个字节
什么是空指针?有什么用?什么是野指针?#
空指针:指针变量指向内存中编号为0的空间。
用途:初始化指针变量 int * p=NULL;
注意:空指针指向的内存不可以访问(0~255之间的内存编号是系统占用的,因此不可访问)
野指针:指针变量指向非法的内存空间。程序中,避免出现野指针。
const修饰指针有哪些情况?有什么区别?#
1、const修饰指针 --- 常量指针
const int * p=&a; 指针指向可以修改,但指针指向的值不可以改。*p=20(X)p=&b(V)
2、const修饰常量 --- 指针常量
int * const p=&a; 指针指向不可以修改,但指针指向的值可以改。*p=20(V)p=&b(X)
【记法:const 和 * 谁在前,对应的就不能变。例如const在前,常量值就不能变;*在前,指针的指向不能变】
3、const既修饰指针又修饰常量
const int * const p=&a; 指针指向不可以修改,但指针指向的值不可以改。*p=20(X)p=&b(X)
int m = 10; int n = 10; const int* pt1 = &m;// 常量指针 pt1 = &n; //*pt1 = 20;// 报错 int* const pt2 = &m;// 指针常量 //pt2 = &n;// 报错 *pt2 = 20; const int* const pt3 = &m;// const既修饰指针又修饰常量 //pt3 = &n;// 报错 //*pt3 = 20;// 报错
如何利用指针访问数组中的元素?#
int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; cout << arr[0] << endl; int* ptr = arr;// arr就是arr数组的首地址 cout << ptr << endl; ptr++;// ptr向后偏移4个字节 cout << ptr << endl; int* ptr2 = arr; for (int i = 0; i < 10; i++) { cout << *ptr2 << " "; ptr2++; }
指针作为函数参数会发生什么情况?#
可以修改实参的值。
// 值传递 void swap(int a, int b) { int temp = b; b = a; a = temp; cout << "内部a= " << a << endl; cout << "内部b= " << b << endl; } // 引用传递 void swap2(int* a, int* b) { int temp = *b; *b = *a; *a = temp; cout << "内部a= " << *a << endl; cout << "内部b= " << *b << endl; } int a = 10; int b = 20; //swap(a, b); 10 20 swap2(&a, &b);20 10 cout << "a= " << a << endl; cout << "b= " << b << endl;
示例:指针结合数组和函数
// 数组的冒泡排序 void bubbleSort(int* arr, int len) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } } // 打印数组 void printArray(int* arr, int len) { for (int i = 0; i < len; i++) { cout << arr[i] << " "; } } int main() { int arr[] = { 3,1,7,4,6,9,10,2,5,8 }; int len = sizeof(arr) / sizeof(arr[0]);// 数组长度 cout << "排序前:"; printArray(arr, len);// 打印数组 cout << endl; bubbleSort(arr, len);// 给数组排序 cout << "排序后:"; printArray(arr, len);// 打印数组 cout << endl; system("pause"); return 0; }
什么是结构体?#
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
struct Student { string name; int age; float score; }; struct Teacher { int id; string name; int age; struct Student stu;// 结构体嵌套 }; // 结构体作值传递 void PrintStudent(struct Student s) { s.age = 100; cout << s.name << " " << s.age << " " << s.score << endl; } // 结构体作引用传递:可以减少空间,不会复制新的副本出来 void PrintStudent2(struct Student* s) { s->age = 200; cout << s->name << " " << s->age << " " << s->score << endl; } // 结构体作引用传递:可以减少空间,不会复制新的副本出来。 // 防止误操作,加const,只能读不能写 void PrintStudent2(const struct Student* s) { cout << s->name << " " << s->age << " " << s->score << endl; } int main() { struct Student s1; s1.name="张三"; s1.age=21; s1.score=100; Student s2={"李四",20,80}; cout<<s1.name<<" "<<s1.age<<" "<<s1.score<<endl; cout<<s2.name<<" "<<s2.age<<" "<<s2.score<<endl; // 结构体数组 Student stus[2] = { s1,s2 }; stus[0].name="张飞"; // 结构体指针 Student * p=&s1; cout<< p->name << " " << p->age << " " << p->score; // 嵌套结构体 Teacher t; t.id=1; t.name="老王"; t.age=40; t.stu=s1; // 结构体作函数参数 cout << "------------------" << endl; PrintStudent(s2); cout << s2.name << " " << s2.age << " " << s2.score << endl; PrintStudent2(&s2); cout << s2.name << " " << s2.age << " " << s2.score << endl; system("pause"); return 0; }
C++核心#
C++的内存分区有哪些?为什么要分区?#
程序运行前:
1、代码区(存放函数体的二进制代码【共享、只读】,由操作系统进行管理)
2、全局区(存放全局变量和静态变量以及常量【字符串常量和const修饰的全局常量】,程序结束时由操作系统释放)
程序运行后:
3、栈区(由编译器自动分配释放,存放函数的参数值,局部变量等)
4、堆区(由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。主要利用new在堆区开辟内存;delete释放)
int * p = new int(10);//*p 存放在栈区,new int(10)存放在堆区 cout<< *P <<endl;//10 delete p; // new、delete开辟数组 int * arr= new int[10]; for(int i=0;i<10;i++) { arr[i]=i+100; } for(int i=0;i<10;i++) { cout<<arr[i]<<endl;//100~109 } delete []arr;
分区存在的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
C++中的引用有什么用?#
给变量起别名。 数据类型 & 别名 = 原名
注意:1、引用必须初始化 2、一旦初始化之后,就不可以更改了。
使用引用作函数参数的优点是什么?#
函数传参时,可以利用引用的技术让形参修饰实参。可以简化指针修改实参。
void swap(int &a,int &b) { int temp = a; a = b; b = temp; } int main() { int m = 10; int n = 20; cout << m << endl;//10 cout << n << endl;//20 swap(m, n); cout << m << endl;//20 cout << n << endl;//10 system("pause"); return 0; }
引用的本质是什么?#
引用的本质在c++内部实现是一个指针常量(指针的指向不能改变,值可以改变)。
为什么会有常量引用?#
常量引用主要用来修饰形参,防止误操作。 const int& a=10; //(X)a=20;
面向对象的三大特性是什么?什么是类?#
封装、继承、多态。
具有相同性质的对象,我们可以抽象为类。
封装有什么意义?#
1、将属性和行为作为一个整体,变现生活中的事物。
2、将属性和行为加以权限控制。A. public公共权限 B. protected 保护权限(子可以访问父) C. private 私有权限
结构体和类的区别是什么?#
c++中,struct和class唯一的区别就在于 默认的访问权限不同。struct 公共;class private
成员属性设置成私有的好处是什么?#
1、可以控制自己读写权限( get,set方法) 2、对于 写,可以检测数据的有效性 (set方法内条件判断)
构造函数和析构函数的作用是什么?#
构造函数:对象的初始化,无需手动调用,只会调用一次
析构函数:在对象销毁前系统自动调用,执行一些清理工作,只会调用一次【在堆区开辟的数据释放掉】
构造函数的调用规则#
-
如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
-
如果用户定义拷贝构造函数,c++不会再提供其他构造函数
深拷贝和浅拷贝是什么?有什么区别?#
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
区别:
浅拷贝的问题:
深拷贝解决:

B类中有对象A作为成员,A为对象成员。那么创建B对象时,A与B的构造和析构的顺序是谁先谁后?#
A的构造——>B的构造——>B的析构——>A的析构
C++静态成员的注意事项#
包括:
静态成员变量:1、所有对象共享同一份数据 2、在编译阶段分配内存(全局区)
3、类内声明,类外初始化 (注意访问权限)int Person::m_A=100; 访问:p.m_A; p1.m_A; Person::m_A;
静态成员函数:(注意访问权限)1、所有对象共享同一个函数 2、静态成员函数只能访问静态成员变量
static void func(){} 访问:p.func(); Person::func();
C++的成员变量和成员函数分开存储。
只有非静态成员变量属于类对象上。sizeof(p)
如果类什么都没有,空对象占1个字节;有非静态成员变量,按照对应变量的大小算
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用同一份代码。
this指针有什么用?#
this指针指向被调用的成员函数所属的对象。本质是指针常量
- 形参和变量成员同名时,可用this指针来区分
- 在类的非static成员函数中返回对象本身,可使用return *this;
const修饰成员函数的用途是什么?#
常函数:1、常函数内不能修改成员属性 2、成员属性声明时加关键字mutable后,在常函数中依然可以修改。
void showPerson() const { }
常对象:常对象只能调用常函数
友元的目的是什么?#
让一个函数或者类 能够访问另一个类中的私有成员。friend
什么是运算符重载?#
对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
使用继承有什么好处?#
减少重复代码 class Java: public BasePage { }
继承方式:1、公共继承 2、保护继承 3、私有继承
父类中所有非静态成员属性都会被子类继承下去。sizeof(son) 包括父类的私有非静态属性
继承中父类和子类的构造和析构顺序谁先谁后?#
Base构造——>Son构造——>Son析构——>Base析构
当子类和父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?#
-
访问子类同名成员,直接访问即可。 s.m_A; s.Func();
-
访问父类同名成员,需要加作用域。 s.Base::m_A; s.Base::Func();
静态成员同名情况下的处理方式一致。
菱形继承问题#
使用 虚继承 解决菱形继承的问题。

哪些属于多态?#
1、静态多态:函数重载 和 运算符重载属于静态多态,复用函数名。 编译阶段确定函数地址
2、动态多态:派生类和虚函数实现运行时多态。 运行阶段确定函数地址
#include <iostream> using namespace std; class Base { public: virtual void speak() { cout << "Base" << endl; } }; class Son1 :public Base { public: //重写Base方法 void speak() { cout << "Son1" << endl; } }; class Son2 :public Base { public: //重写Base方法 void speak() { cout << "Son2" << endl; } }; void Speak(Base& base)//Base& base=son1 { base.speak(); } int main() { Son1 son1; Speak(son1);//Son1 Son2 son2; Speak(son2);//Son2 system("pause"); return 0; }
多态的优点有哪些?#
1、代码组织结构清晰 2、可读性强 3、利于前期和后期的扩展和维护
纯虚函数的由来?什么是抽象类,有什么特点?#
在多态中,通常父类中的虚函数的实现是毫无意义的,主要都是调用子类重写的内容。
可将虚函数改成 纯虚函数。【virtual 返回值类型 speak() = 0;】
当类中有了纯虚函数,这个类也称为抽象类。
- 无法实例化对象
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类。
虚析构和纯虚析构的用处?#
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码。
——使用虚析构或者纯虚析构
virtual ~Base() { } | virtual ~Base() = 0;Base::~Base() { }
共性:1、可以解决父类指针释放子类对象 2、都需要具体的函数实现
区别:如果是纯虚析构,该类属于抽象类,无法实例化对象。
文件操作#
头文件:
ofstream:写操作 ifstream:读操作 fstream:读写操作

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?