✅作者简介:CSDN内容合伙人,全栈领域新星创作者,阿里云专家博主,华为云云享专家博主,掘金后端评审团成员
💕前言:
学长出的这一系列专栏适合有⼀点 C++ 基础,但是⼜不怎么扎实,或者知识点串不起来的同学,说⽩了,这个专栏就是为了拯救 ⾯试突击的你,适合⾯试突击 C++ 后台岗位知识时拿来看,不敢说 100 % 涵盖了⾯试问题,但是⾄少 90%是有的。
再次渡入繁世,人潮汹涌,眼里茫然,信仰永恒,皆为华夏
目录
3、C++ 中 const 和 static 关键字(定义,⽤途)
1、C++ 中内存分配情况
栈:由编译器管理分配和回收,存放局部变ᰁ和函数参数。 堆:由程序员管理,需要⼿动 new malloc delete free 进⾏分配和回收,空间较⼤,但可能会出现内存泄漏和空闲 碎⽚的情况。 全局/静态存储区:分为初始化和未初始化两个相邻区域,存储初始化和未初始化的全局变ᰁ和静态变ᰁ。 常ᰁ存储区:存储常ᰁ,⼀般不允许修改。 代码区:存放程序的⼆进制代码。
2、C++ 中的指针参数传递和引⽤参数传递
指针参数传递本质上是值传递,它所传递的是⼀个地址值。值传递过程中,被调函数的形式参数作为被调函数的局 部变ᰁ处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从⽽形成了实参的⼀个副本(替身)。 值传递的特点是,被调函数对形式参数的任何操作都是作为局部变ᰁ进⾏的,不会影响主调函数的实参变ᰁ的值 (形参指针变了,实参指针不会变)。 引⽤参数传递过程中,被调函数的形式参数也作为局部变ᰁ在栈中开辟了内存空间,但是这时存放的是由主调函数 放进来的实参变ᰁ的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问 主调函数中的实参变ᰁ(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数 中的实参变ᰁ。
引⽤传递和指针传递是不同的,虽然他们都是在被调函数栈空间上的⼀个局部变ᰁ,但是任何对于引⽤参数的处理 都会通过⼀个间接寻址的⽅式操作到主调函数中的相关变ᰁ。⽽对于指针传递的参数,如果改变被调函数中的指针 地址,它将应⽤不到主调函数的相关变ᰁ。如果想通过指针参数传递来改变主调函数中的相关变ᰁ(地址),那就 得使⽤指向指针的指针或者指针引⽤。
从编译的⻆度来讲,程序在编译时分别将指针和引⽤添加到符号表上,符号表中记录的是变ᰁ名及变ᰁ所对应地 址。指针变ᰁ在符号表上对应的地址值为指针变ᰁ的地址值,⽽引⽤在符号表上对应的地址值为引⽤对象的地址值 (与实参名字不同,地址相同)。符号表⽣成之后就不会再改,因此指针可以改变其指向的对象(指针变ᰁ中的值 可以改),⽽引⽤对象则不能修改。
3、C++ 中 const 和 static 关键字(定义,⽤途)
static 作⽤:控制变ᰁ的存储⽅式和可⻅性。
作⽤⼀:
修饰局部变ᰁ:⼀般情况下,对于局部变ᰁ在程序中是存放在栈区的,并且局部的⽣命周期在包含语句块 执⾏结束时便结束了。但是如果⽤ static 关键字修饰的话,该变ᰁ便会存放在静态数据区,其⽣命周期会⼀直延续 到整个程序执⾏结束。但是要注意的是,虽然⽤ static 对局部变ᰁ进⾏修饰之后,其⽣命周期以及存储空间发⽣了 变化,但其作⽤域并没有改变,作⽤域还是限制在其语句块。
作⽤⼆:
修饰全部变ᰁ:对于⼀个全局变ᰁ,它既可以在本⽂件中被访问到,也可以在同⼀个⼯程中其它源⽂件被 访问(添加 extern进⾏声明即可)。⽤ static 对全局变ᰁ进⾏修饰改变了其作⽤域范围,由原来的整个⼯程可⻅变成 了本⽂件可⻅。
作⽤三:
修饰函数:⽤ static 修饰函数,情况和修饰全局变ᰁ类似,也是改变了函数的作⽤域。
作⽤四:
修饰类:如果 C++ 中对类中的某个函数⽤ static 修饰,则表示该函数属于⼀个类⽽不是属于此类的任何 特定对象;如果对类中的某个变ᰁ进⾏ static 修饰,则表示该变ᰁ以及所有的对象所有,存储空间中只存在⼀个副 本,可以通过;类和对象去调⽤。
(补充:静态⾮常ᰁ数据成员,其只能在类外定义和初始化,在类内仅是声明⽽已。)
作⽤五:
类成员/类函数声明 static
函数体内 static 变ᰁ的作⽤范围为该函数体,不同于 auto 变ᰁ,该变ᰁ的内存只被分配⼀次,因此其值在下 次调⽤时仍维持上次的值;
在模块内的 static 全局变ᰁ可以被模块内所⽤函数访问,但不能被模块外其它函数访问;
在模块内的 static 函数只可被这⼀模块内的其它函数调⽤,这个函数的使⽤范围被限制在声明它的模块内;
在类中的 static 成员变ᰁ属于整个类所拥有,对类的所有对象只有⼀份拷⻉;
在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因⽽只能访问类的 static 成员变 ᰁ。
static 类对象必须要在类外进⾏初始化,static 修饰的变ᰁ先于对象存在,所以 static 修饰的变ᰁ要在类外初 始化; 由于 static 修饰的类成员属于类,不属于对象,因此 static 类成员函数是没有 this 指针,this 指针是指向本 对象的指针,正因为没有 this 指针,所以 static 类成员函数不能访问⾮ static 的类成员,只能访问 static修饰 的类成员;
static 成员函数不能被 virtual 修饰,static 成员不属于任何对象或实例,所以加上 virtual 没有任何实际意 义;静态成员函数没有 this 指针,虚函数的实现是为每⼀个对象分配⼀个 vptr 指针,⽽ vptr 是通过 this 指 针调⽤的,所以不能为 virtual;虚函数的调⽤关系,this->vptr->ctable->virtual function。
const 关键字:含义及实现机制
const 修饰基本类型数据类型:基本数据类型,修饰符 const 可以⽤在类型说明符前,也可以⽤在类型说明符后, 其结果是⼀样的。在使⽤这些常ᰁ的时候,只要不改变这些常ᰁ的值即可。
const 修饰指针变ᰁ和引⽤变ᰁ:如果 const 位于⼩星星的左侧,则 const 就是⽤来修饰指针所指向的变ᰁ,即指 针指向为常ᰁ;如果 const 位于⼩星星的右侧,则 const 就是修饰指针本身,即指针本身是常ᰁ。
const 应⽤到函数中:作为参数的 const 修饰符:调⽤函数的时候,⽤相应的变ᰁ初始化 const 常ᰁ,则在函数体 中,按照 const 所修饰的部分进⾏常ᰁ化,保护了原对象的属性。 [注意]:参数 const 通常⽤于参数为指针或引⽤ 的情况; 作为函数返回值的 const 修饰符:声明了返回值后,const 按照"修饰原则"进⾏修饰,起到相应的保护作 ⽤。
const 在类中的⽤法:const 成员变ᰁ,只在某个对象⽣命周期内是常ᰁ,⽽对于整个类⽽⾔是可以改变的。因为 类可以创建多个对象,不同的对象其 const 数据成员值可以不同。所以不能在类的声明中初始化 const 数据成员, 因为类的对象在没有创建时候,编译器不知道 const 数据成员的值是什么。const 数据成员的初始化只能在类的构 造函数的初始化列表中进⾏。const 成员函数:const 成员函数的主要⽬的是防⽌成员函数修改对象的内容。要注 意,const 关键字和 static 关键字对于成员函数来说是不能同时使⽤的,因为 static 关键字修饰静态成员函数不含 有 this 指针,即不能实例化,const 成员函数⼜必须具体到某⼀个函数。
const 修饰类对象,定义常ᰁ对象:常ᰁ对象只能调⽤常ᰁ函数,别的成员函数都不能调⽤。
补充:const 成员函数中如果实在想修改某个变ᰁ,可以使⽤ mutable 进⾏修饰。成员变ᰁ中如果想建⽴在整个类 中都恒定的常ᰁ,应该⽤类中的枚举常ᰁ来实现或者 static const。
C ++ 中的 const类成员函数(⽤法和意义)
常ᰁ对象可以调⽤类中的 const 成员函数,但不能调⽤⾮ const 成员函数; (原因:对象调⽤成员函数时,在形 参列表的最前⾯加⼀个形参 this,但这是隐式的。this 指针是默认指向调⽤函数的当前对象的,所以,很⾃然,
this 是⼀个常ᰁ指针 test * const,因为不可以修改 this 指针代表的地址。但当成员函数的参数列表(即⼩括号) 后加了 const 关键字(void print() const;),此成员函数为常ᰁ成员函数,此时它的隐式this形参为 const test * const,即不可以通过 this 指针来改变指向对象的值。
⾮常ᰁ对象可以调⽤类中的 const 成员函数,也可以调⽤⾮ const 成员函数。