目录
指针和引用的区别
指针存放某个对象的地址,其本身就是变量(命了名的对象),本身就有地址,所以可以有指向指针的指针;可变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变
引用就是变量的别名,从⼀⽽终,不可变,必须初始化
不存在指向空值的引⽤,但是存在指向空值的指针
1. 定义和声明:
指针是⼀个变量,其值是另⼀个变量的地址。声明指针时,使⽤ * 符号。
int x = 10;
int *ptr = &x;
引用是⼀个别名,它是在已存在的变量上创建的。在声明引⽤时,使⽤ & 符号。
int y = 20;
int &ref = y;
2. 使用和操作:
指针: 可以通过解引⽤操作符 * 来访问指针指向的变量的值,还可以通过地址运算符 & 获取变量的地址。
int value = *ptr; // 获取指针指向的值
int address = &x; // 获取变量 x 的地址
引用: 引⽤在声明时被初始化,并在整个⽣命周期中⼀直引⽤同⼀个变量。不需要使⽤解引⽤操作符,因为引⽤本身就是变量的别名
int newValue = ref; // 获取引⽤的值
3. 空值和空引用:
指针可以为空(nullptr)表示不指向任何有效的地址。
引用必须在声明时初始化,并且不能在后续改变引⽤的绑定对象。因此,没有空引⽤的概念
4. 可变性:
指针: 可以改变指针的指向,使其指向不同的内存地址。
引用: ⼀旦引⽤被初始化,它将⼀直引⽤同⼀个对象,不能改变绑定。
5. 用途:
指针: 通常⽤于动态内存分配、数组操作以及函数参数传递。
引用: 通常⽤于函数参数传递、操作符重载以及创建别名。
数据类型
整型 short int long 和 long long
C++ 整型数据⻓度标准
short ⾄少 16 位
int ⾄少与 short ⼀样⻓
long ⾄少 32 位,且⾄少与 int ⼀样⻓
long long ⾄少 64 位,且⾄少与 long ⼀样⻓
在使⽤8位字节的系统中,1 byte = 8 bit
很多系统都使⽤最⼩⻓度,short 为 16 位即 2 个字节,long 为 32 位即 4 个字节,long long 为 64 位即 8 个字 节,int 的⻓度较为灵活,⼀般认为 int 的⻓度为 4 个字节,与 long 等⻓。 可以通过运算符 sizeof 判断数据类型的⻓度。例如:
cout << "int is " << sizeof (int) << " bytes. \n";
cout << "short is " << sizeof (short) << " bytes. \n";
头⽂件climits定义了符号常量:例如:INT_MAX 表示 int 的最⼤值,INT_MIN 表示 int 的最⼩值。
无符号类型
即为不存储负数值的整型,可以增⼤变量能够存储的最⼤值,数据⻓度不变。
int 被设置为⾃然⻓度,即为计算机处理起来效率最⾼的⻓度,所以选择类型时⼀般选⽤ int 类型。
常量指针和指针常量的区别
- 常量指针是指针所指向的内容是常量,指针本身可变。
- 指针常量是指针本身是常量,所指的内容可变。
- 在常量指针中, const 关键字位于 * 之前。
- 在指针常量中, const 关键字位于 * 之后。
常量指针是指指针所指向的内容是⼀个常量,即指针所指向的内容不能被修改,但指针本身的值(地址)可以被修改。
int x = 10;
int y = 20;
// 定义:const int *ptr = &x; 或 int const *ptr = &x;
const int *ptr = &x; // 常量指针,不可以修改指针所指向的内容,可修改指针的值
// *ptr = 30; // 错误,不能修改指针所指向的内容
ptr = &y; // 正确,可修改指针的值
指针常量是指指针本身是⼀个常量,即指针的值(地址)不能被修改,但它所指向的内容可以被修改。
int x = 10;
int y = 20;
int *const ptr = &x; // 指针常量,可以修改指针所指向的内容,不能修改指针的值
*ptr = 30; // 正确,可以修改指针所指向的内容
// ptr = &y; // 错误,不能修改指针的值
什么是函数指针,如何定义和使用场景?
函数指针是指向函数的指针变量。它可以⽤于存储函数的地址,允许在运⾏时动态选择要调⽤的函数。
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int main() {
// 定义⼀个函数指针,指向⼀个接受两个int参数、返回int的函数
// 返回类型 (*指针变量名)(参数列表)
int (*operationPtr)(int, int);
// 初始化函数指针,使其指向 add 函数
operationPtr = &add;
// 通过函数指针调⽤函数
int result = operationPtr(10, 5);
cout << "Result: " << result << endl;
// 将函数指针切换到 subtract 函数
operationPtr = &subtract;
// 再次通过函数指针调⽤函数
result = operationPtr(10, 5);
cout << "Result: " << result << endl;
return 0;
}
使⽤场景:
- 回调函数: 函数指针常⽤于实现回调机制,允许将函数的地址传递给其他函数,以便在适当的时候调⽤。
- 函数指针数组: 可以使⽤函数指针数组实现类似于状态机的逻辑,根据不同的输⼊调⽤不同的函数。
- 动态加载库: 函数指针可⽤于在运⾏时动态加载库中的函数,实现动态链接库的调⽤。
- 多态实现: 在C++中,虚函数和函数指针结合使⽤,可以实现类似于多态的效果。
- 函数指针作为参数: 可以将函数指针作为参数传递给其他函数,实现⼀种可插拔的函数⾏为。
- 实现函数映射表: 在⼀些需要根据某些条件调⽤不同函数的情况下,可以使⽤函数指针来实现函数映射表。
函数指针和指针函数的区别
函数指针是指向函数的指针变量。可以存储特定函数的地址,并在运⾏时动态选择要调⽤的函数。通常⽤于回调函数、动态加载库时的函数调⽤等场景。
int add(int a, int b) {
return a + b;
}
int (*ptr)(int, int) = &add; // 函数指针指向 add 函数
int result = (*ptr)(3, 4); // 通过函数指针调⽤函数
指针函数是⼀个返回指针类型的函数,⽤于返回指向某种类型的数据的指针。
int* getPointer() {
int x = 10;
return &x; // 返回局部变ᰁ地址,不建议这样做
}
struct和Class的区别
- 通常, struct ⽤于表示⼀组相关的数据,⽽ class ⽤于表示⼀个封装了数据和操作的对象,在实际使⽤中,可以根据具体的需求选择使⽤ struct 或 class 。如果只是⽤来组织⼀些数据,⽽不涉及复杂的封装和继承关系, struct 可能更直观;如果需要进⾏封装、继承等⾯向对象编程的特性,可以选择使⽤ class 。
- struct 结构体中的成员默认是公有的(public)。类中的成员默认是私有的(private)。
- struct 继承时默认使⽤公有继承。class 继承时默认使⽤私有继承。
- 如果结构体没有定义任何构造函数,编译器会⽣成默认的⽆参数构造函数。如果类没有定义任何构造函数,编译器也会⽣成默认的⽆参数构造函数。
// 使⽤ struct 定义
struct MyStruct {
int x; // 默认是 public
void print() {
cout << "Struct method" << endl;
}
};
// 使⽤ class 定义
class MyClass {
public: // 如果省略,默认是 private
int y;
void display() {
cout << "Class method" << endl;
}
};
静态局部变量\全局变量\局部变量的区别和使用场景
1. 静态局部变量
- 作⽤域: 限定在定义它的函数内。
- ⽣命周期: 与程序的⽣命周期相同,但只能在定义它的函数内部访问。
- 关键字: 使⽤ static 关键字修饰。
- 初始化: 仅在第⼀次调⽤函数时初始化,之后保持其值。
当希望在函数调⽤之间保留变量的值,并且不希望其他函数访问这个变量时,可以使⽤静态局部变量。
void exampleFunction() {
static int count = 0; // 静态局部变量
count++;
cout << "Count: " << count << endl;
}
// 注意:当我们多次调用 exampleFunction() 函数时,count 变量的值会累加,而不是每次都从 0 开始。
2. 全局变量
- 作⽤域: 整个程序。
- ⽣命周期: 与程序的⽣命周期相同。
- 关键字: 定义在全局作⽤域,不使⽤特定关键字。
当多个函数需要共享相同的数据时,可以使⽤全局变量。
int globalVar = 10; // 全局变量
void function1() {
globalVar++;
}
void function2() {
globalVar--;
}
3. 局部变量
- 作⽤域: 限定在定义它的块(⼤括号内)。
- ⽣命周期: 在块结束时销毁。
- 关键字: 定义在函数、语句块或类的成员函数中。
当变量只在某个特定作⽤域内有效,并且不需要其他作⽤域访问时,可以使⽤局部变量。
总结
- 静态局部变量⽤于在函数调⽤之间保留变量的值。
- 全局变量适⽤于多个函数需要共享的数据。
- 局部变类适⽤于仅在特定作⽤域内有效的情况。
C++强制类型转换
关键字:static_cast 、dynamic_cast 、reinterpret_cast 和 const_cast
1. static_cast
没有运⾏时类型检查来保证转换的安全性
进⾏上⾏转换(把派⽣类的指针或引⽤转换成基类表示)是安全的;
进⾏下⾏转换(把基类的指针或引⽤转换为派⽣类表示),由于没有动态类型检查,所以是不安全的。
使⽤:
- ⽤于基本数据类型之间的转换,如把int转换成char。
- 把任何类型的表达式转换成void类型。
2. dynamic_cast
在进⾏下⾏转换时,dynamic_cast具有类型检查(信息在虚函数中)的功能,⽐static_cast更安全。
转换后必须是类的指针、引⽤或者void*,基类要有虚函数,可以交叉转换。
dynamic本身只能⽤于存在虚函数的⽗⼦关系的强制类型转换;对于指针,转换失败则返回nullptr,对于引⽤,转换失败会抛出异常。
3. reinterpret_cast
可以将整型转换为指针,也可以把指针转换为数组;可以在指针和引⽤⾥进⾏肆⽆忌惮的转换,平台移植性⽐价差。
4. const_cast
常量指针转换为⾮常量指针,并且仍然指向原来的对象。常量引⽤被转换为⾮常量引⽤,并且仍然指向原来的对象。去掉类型的const或volatile属性。