点击蓝字
关注我们
C++ 基础
1、引用和指针的区别?
初始化:
引用在定义的时候必须进行初始化,并且不能够改变
指针在定义的时候不一定要初始化,并且指向的空间可变
访问逻辑不同:
通过指针访问对象, 用户需要使用间接访问
通过引用访问对象, 用户只需使用直接访问, 编译器负责将其处理为间接访问
运算结果不同:
传指针的实质是传值,传递的值是指针内储存的变量地址;
传引用的实质是传地址,传递的是变量的地址。
指针通过下标运算结果是指针所指值为基地址加上偏移, 且基地址可变.
引用通过下标运算结果是引用的是数组才能有这个操作.
自增运算结果不同
`sizeof`运算的结果不同
下标运算:
函数参数:
多级: 有多级指针,但是没有多级引用,只能有一级引用。
2、从汇编层去解释一下引用
参考两个语句
mov ptr [ebp-4], 1 lea eax, [ebp-4] mov dword ptr [ebp-8], eax ```
a
的地址为ebp-4
,b
的地址为ebp-8
, 栈地址由高到底分配.可以发现这个和指针的复制几乎一样,所以引用其实是通过指针来实现的
3、C++中的指针参数传递和引用参数传递
指针参数传递的本质是值传递, 传递的值是对象的地址, 在调用时形参会在函数栈中开辟空间用于存放传递过来的对象的地址,此时形参相当于是实参的副本, 对形参的任何操作都不会反映到实参上, 但是通过形参间接访问对象的修改是会反应到函数之外的.
引用参数传递的本质是传地址, 传递的是实参变量的地址, 首先形参会在函数栈中开辟空间用来存放实参变量的地址, 然后对该形参的任何操作都会被处理未间接寻址,即通过形参中的地址访问主调函数中的实参变量, 因为通过形参的任何操作都将被应用于主调函数中.
从逻辑上引用相当于对变量起了一个别名, 通过该别名可以对变量进行直接访问, 由编译器负责将直接访问转换为间接访问; 而指针访问变量都是间接访问.
4、形参与实参的区别?
形参属于函数内部的局部变量, 在调用函数时才会分配内存, 在函数调用之后会被释放掉, 因此在函数内部才有效
实参可以使常量, 表达式, 函数等, 无论是何种类型,在函数调用时都必须有一个确定的值,以便把函数的值传递给形参
实参和形参的个数一定要严格匹配(当然可以忽略有默认值形参), 通常情况下函数类型也是应该严格匹配的, 但是允许隐式类型变换,如果类中定义了零参数构造函数,甚至可以使用空初始化列表
{}
的方式调用零参数构造函数实参到形参的传递是单向的
形参类型为非指针非引用, 则传递方式为值传递则, 形参为实参的副本, 对形参的任何修改都不会反应在主调函数中
4-2 三种传递方式
值传递是通过拷贝构造函数实现的
指针传递是属于值传递,实参指针向形参传递的是对象的地址
引用传是属于传地址, 相当于对变量起了一个别名, 本质上和指针传递类似传递的都是对象的地址,区别在于对该引用形参的任何操作都会被处理为间接云芝, 也就是会反应到调用函数中
5、`static`的用法
主要可以分为五个类型: 全局静态变量, 局部静态变量, 静态函数, 静态成员变量, 静态成员函数
当定义它的函数或者语句块结束的时候,作用域结束。
但是当局部静态变量离开作用域后,并没有销毁,而是仍然驻留在内存当中,只不过我们不能再对它进行访问,直到该函数再次被调用,并且值不变;
在全局变量前加上关键字
static
,全局变量就定义成一个全局静态变量.内存中的位置:静态存储区,在整个程序运行期间一直存在。
初始化:未经初始化的全局静态变量会被自动初始化为
0
(对于自动对象,如果没有显示初始化,会调用零参数构造函数,如不存在则编译失败);作用域:全局静态变量在声明他的文件之外是不可见的,准确地说是从定义之处开始,到文件结尾。
在局部变量之前加上关键字
static
,局部变量就成为一个局部静态变量。内存中的位置:静态存储区
初始化:未经初始化的全局静态变量会被自动初始化为
0
(对于自动对象,如果没有显示初始化,会调用零参数构造函数,如不存在则编译失败);作用域:作用域仍为局部作用域,
局部静态变量
全局静态变量
静态函数
在函数返回类型前加`static`,函数就定义为静态函数。函数的定义和声明在默认情况下都是`extern`的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。
函数的实现使用`static`修饰,那么这个函数只可在本`cpp`内使用,不会同其他`cpp`中的同名函数引起冲突;
`warning`:不要再头文件中声明`static`的全局函数,不要在`cpp`内声明非`static`的全局函数,如果你要在多个`cpp`中复用该函数,就把它的声明提到头文件里去,否则`cpp`内部声明需加上`static`修饰;
类的静态成员
在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。
因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用
类的静态函数
静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员(这点非常重要)。*如果静态成员函数中要引用非静态成员时,可通过对象来引用。从中可看出,调用静态成员函数使用如下格式:::();*参数表>静态成员函数名>类名>
不能被`virtual`修饰,静态成员函数没有`this` 指针,虚函数的实现是为每一个对象分配一个`vptr` 指针,而`vptr` 是通过`this` 指针调用的,所以不能为`virtual`;虚函数的调用关系,`this`->`vptr`->`ctable`->`virtual function`
6、静态变量什么时候初始化
静态局部变量和全局变量一样,数据都存放在全局区域,所以在主程序之前,编译器已经为其分配好了内存,
但在
C
和C++
中静态局部变量的初始化节点又有点不太一样。在`C`中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到==在`C` 语言中无法使用变量对静态局部变量进行初始化==,在程序运行结束,变量所处的全局内存会被全部回收。
而在`C++`中,初始化时在执行相关代码时才会进行初始化,主要是由于`C++`引入对象后,要进行初始化必须执行相应构造函数和析构函数,在构造函数或析构函数中经常会需要进行某些程序中需要进行的特定操作,并非简单地分配内存。所以 `C++`标准规定为全局或静态对象是有首次用到时才会进行构造 ,并通过`atexit()`来管理。在程序结束,按照构造顺序反方向进行逐个析构。所以在 `C++`中是可以使用变量对静态局部变量进行初始化的。
7、const?
一般可以分为如下六种类型
`const`变量: 表明标了为`const`类型, 通常需要被初始化否则后面将不能被修改, 对该变量的修改操作都会被编译器阻止.
`const`指针对象: 标明该指针为普通的左值类型可以进行修改, 但是不能通过该变量修改做指向的对象, 则通过该指针只能访问`const`类型的成员函数.
`const`引用: 它所绑定的对象不能被修改
`const`形参: 和普通的实参分类一样分为const 变量, const指针对象, const 引用, 作用也类似,表示不能修改该变量.
`const`返回值: 通常是为了表明返回值是一个const类型防止返回值被修改, 或则被当做左值放在赋值运算的左边
`const`成员函数: 是指成员函数不会修改类对象的任何成员变量, 如果返回值为对象成员的引用则必须返回`const`引用, 同时`const`成员函数不能调用非`const`函数, 其主要是因为`const`成员函数所持有的`this`指针是一个`const`类型的指针, 因为不能调用非`const`类型的成员函数,
8、`const` 成员函数的理解和应用?
① const Stock & Stock::topval (②const Stock & s) ③const
① 处
const
:确保返回的Stock
对象在以后的使用中不能被修改② 处
const
:确保此方法不修改传递的参数s
③ 处
const
:保证此方法不修改调用它的对象,const
对象只能调用const
成员函数,不能调用非const
函数
9、指针和`const`的用法
当
const
修饰指针时,由于const
的位置不同,它的修饰对象会有所不同。(常指针对象)
int const p2` 中`const` 修饰`p2` 的值,所以理解为`p2` 的值不可以改变,即`p2` 只能指向固定的一个变量地址,但可以通过`p2
读写这个变量的值。顶层指针表示指针本身是一个常量(常指针)
int const *p1
或者const int *p1
两种情况中const
修饰p1`,所以理解为`p1
的值不可以改变,即不可以给*p1
赋值改变p1
指向变量的值,但可以通过给p
赋值不同的地址改变这个指针指向。底层指针表示指针所指向的变量是一个常量。
10、`mutable`
如果需要在
const
成员方法中修改一个成员变量的值,那么需要将这个成员变量修饰为mutable
。即用`mutable` 修饰的成员变量不受`const` 成员方法的限制;可以认为
mutable
的变量是类的辅助状态,但是只是起到类的一些方面表述的功能,修改他的内容我们可以认为对象的状态本身并没有改变的。实际上由于const_cast
的存在,这个概念很多时候用处不是很到了。
通常情况下
`const`成员函数时不能被类对象的成员变量的, 但是可以修改被`mutable`修饰的成员变量
通常我们任务`mutable`位类的辅助状态, 只是类的一些表诉功能, 修改它不会改变对象的状态
通常我们可以是用`const_cast`在`const`成员函数中修改所有的成员变量
*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。
戳“阅读原文”我们一起进步