C++八股文基础(二)—— 关键字(const、static、define、typedef、inline、new、malloc、constexpr、volatile、extern、前置++和后置++)

const 关键字

const的作⽤:
被它修饰的值不能改变,是只读变量。必须在定义的时候就给它赋初值。

1、常量指针(底层const )

常量指针:
是指定义了⼀个指针,这个指针指向⼀个只读的对象,不能通过常量指针来改变这个对象的值。常量指针强调的是
指针对其所指对象的不可改变性。
特点:
靠近变量名。
形式:
(1)const 数据类型 *指针变量 = 变量名
(2)数据类型 const *指针变量 = 变量名
示例:

int temp = 10; 
const int* a = &temp;
int const *a = &temp;
// 更改:
*a = 9; // 错误:只读对象
temp = 9; // 正确

2、指针常量(顶层const)

指针常量:
指针常量是指定义了⼀个指针,这个指针的值只能在定义时初始化,其他地⽅不能改变。指针常量强调的是指针的
不可改变性。
特点:
靠近变量类型。
形式:
数据类型 * const 指针变量=变量名
示例:

int temp = 10; 
int temp1 = 12; 
int* const p = &temp;
// 更改:
p = &temp2; // 错误
*p = 9; // 正确

static关键字的作⽤

static 关键字主要⽤于控制变量和函数的⽣命周期、作⽤域以及访问权限。
1. 静态变量

  • 在函数内部使⽤static关键字修饰的变量称为静态变量。
  • 静态变量在程序的整个⽣命周期内存在,不会因为离开作⽤域⽽被销毁。
  • 静态变ᰁ默认初始化为零(对于基本数据类型)。
void exampleFunction() {
	static int count = 0; // 静态变量
	count++;
	cout << "Count: " << count << endl;
}
  1. 静态函数
  • 在类内部使⽤ static 关键字修饰的函数是静态函数。
  • 静态函数属于类⽽不是类的实例,可以通过类名直接调⽤,⽽⽆需创建对象。
  • 静态函数不能直接访问⾮静态成员变量或⾮静态成员函数。
class ExampleClass {
public:
	static void staticFunction() {
	cout << "Static function" << endl;
	}
};
  1. 静态成员变量
  • 在类中使⽤ static 关键字修饰的成员变量是静态成员变量。
  • 所有类的对象共享同⼀个静态成员变量的副本。
  • 静态成员变量必须在类外部单独定义,以便为其分配存储空间。
class ExampleClass {
public:
	static int staticVar; // 静态成员变量声明
};
// 静态成员变ᰁ定义
int ExampleClass::staticVar = 0;
  1. 静态成员函数
  • 在类中使⽤ static 关键字修饰的成员函数是静态成员函数。
  • 静态成员函数不能直接访问⾮静态成员变ᰁ或⾮静态成员函数。
  • 静态成员函数可以通过类名调⽤,⽽不需要创建类的实例。
class ExampleClass {
public:
	static void staticMethod() {
	cout << "Static method" << endl;
	}
};
  1. 静态局部变量
  • 在函数内部使⽤ static 关键字修饰的局部变量是静态局部变量。
  • 静态局部变量的⽣命周期延⻓到整个程序的执⾏过程,但只在声明它的函数内可⻅。
void exampleFunction() {
	static int localVar = 0; // 静态局部变量
	localVar++;
	cout << "LocalVar: " << localVar << endl;
}

const关键字的作用

const 关键字主要⽤于指定变量、指针、引⽤、成员函数等的性质

  1. 常量变量:声明常量,使变量的值不能被修改。
  2. 指针和引用:声明指向常量的指针,表示指针所指向的值是常量,不能通过指针修改。声明常量引⽤,表示引⽤的值是常量,不能通过引⽤修改。
const int* ptr = &constantValue; // 指向常量的指针
const int& ref = constantValue; // 常量引⽤
  1. 成员函数:⽤于声明常量成员函数,表示该函数不会修改对象的成员变量(对于成员变量是⾮静态的情况)。
  2. 常量对象:声明对象为常量,使得对象的成员变量不能被修改。
  3. 常引⽤参数:声明函数参数为常量引⽤,表示函数不会修改传⼊的参数。
  4. 常量指针参数:声明函数参数为指向常量的指针,表示函数不会通过指针修改传⼊的数据。

define 和 typedef 的区别

define

  1. 只是简单的字符串替换,没有类型检查
  2. 是在编译的预处理阶段起作⽤
  3. 可以⽤来防⽌头⽂件重复引⽤
  4. 不分配内存,给出的是⽴即数,有多少次使⽤就进⾏多少次替换

typedef

  1. 有对应的数据类型,是要进⾏判断的
  2. 是在编译、运⾏的时候起作⽤
  3. 在静态存储区中分配空间,在程序运⾏过程中内存中只有⼀个拷⻉

define 和 inline 的区别

1、define:

定义预编译时处理的宏,只是简单的字符串替换,⽆类型检查,不安全。

2、inline:

inline是先将内联函数编译完成⽣成了函数体直接插⼊被调⽤的地⽅,减少了压栈,跳转和返回的操作。没有普通
函数调⽤时的额外开销;
内联函数是⼀种特殊的函数,会进⾏类型检查;
对编译器的⼀种请求,编译器有可能拒绝这种请求;
C++中inline编译限制

  1. 不能存在任何形式的循环语句
  2. 不能存在过多的条件判断语句
  3. 函数体不能过于庞⼤
  4. 内联函数声明必须在调⽤语句之前

const和define的区别

const⽤于定义常量;⽽define⽤于定义宏,⽽宏也可以⽤于定义常量。都⽤于常量定义时,它们的区别有:

  1. const⽣效于编译的阶段;define⽣效于预处理阶段。
  2. const定义的常量,在C语⾔中是存储在内存中、需要额外的内存空间的;define定义的常量,运⾏时是直接
    的操作数,并不会存放在内存中。
  3. const定义的常量是带类型的;define定义的常量不带类型。因此define定义的常量不利于类型检查。

new 和 malloc的区别

1、new内存分配失败时,会抛出bac_alloc异常,它不会返回NULLmalloc分配内存失败时返回NULL
2、使⽤new操作符申请内存分配时⽆须指定内存块的⼤⼩,⽽malloc则需要显式地指出所需内存的尺⼨。
3、opeartor new /operator delete可以被重载,⽽malloc/free并不重载。
4、new/delete会调⽤对象的构造函数/析构函数以完成对象的构造/析构。⽽malloc则不会
5、mallocfree是C++/C语⾔的标准库函数,newdelete是C++的运算符
6、new操作符从⾃由存储区上为对象动态分配内存空间,⽽malloc函数从堆上动态分配内存。
表格
new和malloc区别

constexpr 和 const

const 表示“只读”的语义,constexpr 表示“常量”的语义
constexpr 只能定义编译期常量,⽽ const 可以定义编译期常量,也可以定义运⾏期常量。
你将⼀个成员函数标记为constexpr,则顺带也将它标记为了const。如果你将⼀个变量标记为constexpr,则同样它是const的。但相反并不成⽴,⼀个const的变量或函数,并不是constexpr的。

constexpr变量

复杂系统中很难分辨⼀个初始值是不是常量表达式,可以将变量声明为constexpr类型,由编译器来验证变量的值是否是⼀个常量表达式。
必须使⽤常量初始化:

constexpr int n = 20;
constexpr int m = n + 1;
static constexpr int MOD = 1000000007;

如果constexpr声明中定义了⼀个指针,constexpr仅对指针有效,和所指对象⽆关。

constexpr int *p = nullptr; //常ᰁ指针 顶层const
const int *q = nullptr; //指向常ᰁ的指针, 底层const
int *const q = nullptr; //顶层const

constexpr函数:

constexpr函数是指能⽤于常ᰁ表达式的函数。
函数的返回类型和所有形参类型都是字⾯值类型,函数体有且只有⼀条return语句。

constexpr int new() {return 42;}

为了可以在编译过程展开,constexpr函数被隐式转换成了内联函数。
constexpr和内联函数可以在程序中多次定义,⼀般定义在头⽂件。

constexpr 构造函数:

构造函数不能说const,但字⾯值常ᰁ类的构造函数可以是constexpr。
constexpr构造函数必须有⼀个空的函数体,即所有成员变ᰁ的初始化都放到初始化列表中。对象调⽤的成员函数
必须使⽤ constexpr 修饰
const:
指针常量: const int* d = new int(2);
常量指针: int *const e = new int(2);
区别⽅法:
左定值,右定向:指的是const在*的左还是右边
拓展:
顶层const:指针本身是常量;
底层const:指针所指的对象是常量;
若要修改const修饰的变量的值,需要加上关键字volatile
若想要修改const成员函数中某些与类状态⽆关的数据成员,可以使⽤mutable关键字来修饰这个数据成员;
『const和static的区别』
const和static的区别

constexpr的好处

  1. 为⼀些不能修改数据提供保障,写成变ᰁ则就有被意外修改的⻛险。
  2. 有些场景,编译器可以在编译期对constexpr的代码进⾏优化,提⾼效率。
  3. 相⽐宏来说,没有额外的开销,但更安全可靠。

volatile

定义:
与const绝对对⽴的,是类型修饰符]影响编译器编译的结果,⽤该关键字声明的变量表示该变量随时可能发⽣变化,与该变量有关的运算,不要进⾏编译优化;会从内存中量新装载内容,⽽不是直接从寄存器拷⻉内容。
作⽤:
指令关键字,确保本条指令不会因编译器的优化⽽省略,且要求每次直接读值,保证对特殊地址的稳定访问
使⽤场合:
在中断服务程序和cpu相关寄存器的定义
举例说明:
空循环:

for(volatile int i=0; i<100000; i++); // 它会执⾏,不会被优化掉 

extern

定义:声明外部变量【在函数或者⽂件外部定义的全局变量】

static

作⽤:实现多个对象之间的数据共享 + 隐藏,并且使⽤静态成员还不会破坏隐藏原则;默认初始化为0

前置++与后置++

为了区分前后置,重载函数是以参数类型来区分,在调⽤的时候,编译器默默给int指定为⼀个0
1、为什么后置返回对象,⽽不是引⽤
因为后置为了返回旧值创建了⼀个临时对象,在函数结束的时候这个对象就会被销毁,如果返回引⽤,那么我请问
你?你的对象对象都被销毁了,你引⽤啥呢?
2、为什么后置前⾯也要加const
其实也可以不加,但是为了防⽌你使⽤i++++,连续两次的调⽤后置++᯿载符,为什么呢?
原因:
它与内置类型⾏为不⼀致;你⽆法活得你所期望的结果,因为第⼀次返回的是旧值,⽽不是原对象,你调⽤两次后
置++,结果只累加了⼀次,所以我们必须⼿动禁⽌其合法化,就要在前⾯加上const。
3、处理⽤户的⾃定义类型
最好使⽤前置++,因为他不会创建临时对象,进⽽不会带来构造和析构⽽造成的格外开销。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J^T

谢谢帅哥/美女

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值