欢迎关注
0voice · GitHub
18
、
volatile
和
extern
关键字
volatile
三个特性
易变性:在汇编层⾯反映出来,就是两条语句,下⼀条语句不会直接使⽤上⼀条语句对应的
volatile
变ᰁ的寄存器
内容,⽽是᯿新从内存中读取。
不可优化性:
volatile
告诉编译器,不要对我这个变ᰁ进⾏各种激进的优化,甚⾄将变ᰁ直接消除,保证程序员写
在代码中的指令,⼀定会被执⾏。
顺序性:能够保证
volatile
变ᰁ之间的顺序性,编译器不会进⾏乱序优化。
extern
在
C
语⾔中,修饰符
extern
⽤在变ᰁ或者函数的声明前,⽤来说明
“
此变ᰁ
/
函数是在别处定义的,要在此处引
⽤
”
。
注意
extern
声明的位置对其作⽤域也有关系,如果是在
main
函数中进⾏声明的,则只能在
main
函数中调⽤,在
其它函数中不能调⽤。其实要调⽤其它⽂件中的函数和变ᰁ,只需把该⽂件⽤
#include
包含进来即可,为啥要⽤
extern
?因为⽤
extern
会加速程序的编译过程,这样能节省时间。
在
C++
中
extern
还有另外⼀种作⽤,⽤于指示
C
或者
C
++函数的调⽤规范。⽐如在
C
++ 中调⽤
C
库函数,就
需要在
C
++ 程序中⽤
extern “C”
声明要引⽤的函数。这是给链接器⽤的,告诉链接器在链接的时候⽤
C
函数规范
来链接。主要原因是
C
++ 和
C
程序编译完成后在⽬标代码中命名规则不同,⽤此来解决名字匹配的问题。
19
、
define
和
const
区别(编译阶段、安全性、内存占⽤等)
对于
define
来说,
宏定义实际上是在预编译阶段进⾏处理,没有类型,也就没有类型检查,仅仅做的是遇到宏定
义进⾏字符串的展开,遇到多少次就展开多少次,⽽且这个简单的展开过程中,很容易出现边界效应,达不到预期
的效果。因为
define
宏定义仅仅是展开,因此运⾏时系统并不为宏定义分配内存,但是从汇编 的⻆度来讲,
define
却以⽴即数的⽅式保留了多份数据的拷⻉。
对于
const
来说,
const
是在编译期间进⾏处理的,
const
有类型,也有类型检查,程序运⾏时系统会为
const
常
ᰁ分配内存,⽽且从汇编的⻆度讲,
const
常ᰁ在出现的地⽅保留的是真正数据的内存地址,只保留了⼀份数据的
拷⻉,省去了不必要的内存空间。⽽且,有时编译器不会为普通的
const
常ᰁ分配内存,⽽是直接将
const
常ᰁ添
加到符号表中,省去了读取和写⼊内存的操作,效率更⾼。
20
、计算下⾯⼏个类的⼤⼩
class
A
{};
sizeof
(
A
)
=
1
;
//
空类在实例化时得到⼀个独⼀⽆⼆的地址,所以为
1.
class
A
{
virtual
Fun
(){} };
sizeof
(
A
)
=
4
(
32bit
)
/
8
(
64bit
)
//
当
C++
类中有虚函数的时候,会有⼀
个指向虚函数表的指针(
vptr
)
class
A
{
static
int
a
; };
sizeof
(
A
)
=
1
;
class
A
{
int
a
; };
sizeof
(
A
)
=
4
;
class
A
{
static
int
a
;
int
b
; };
sizeof
(
A
)
=
4
;
21
、⾯向对象的三⼤特性,并举例说明
C++
⾯向对象的三⼤特征是:封装、继承、多态。
所谓封装
就是把客观事物封装成抽象的类,并且类可以把⾃⼰的数据和⽅法只让信任的类或者对象操作,对不可信的进⾏信
息隐藏。⼀个类就是⼀个封装了数据以及操作这些数据的代码的逻辑实体。在⼀个对象内部,某些代码或某些数据
可以是私有的,不能被外界访问。通过这种⽅式,对象对内部数据提供了不同级别的保护,以防⽌程序中⽆关的部
分意外的改变或错误的使⽤了对象的私有部分。
所谓继承
是指可以让某个类型的对象获得另⼀个类型的对象的属性的⽅法。它⽀持按级分类的概念。继承是指这样⼀种能
⼒:它可以使⽤现有类的所有功能,并在⽆需᯿新编写原来的类的情况下对这些功能进⾏扩展。通过继承创建的新
类称为
“
⼦类
”
或者
“
派⽣类
”
,被继承的类称为
“
基类
”
、
“
⽗类
”
或
“
超类
”
。继承的过程,就是从⼀般到特殊的过程。要
实现继承,可以通过
“
继承
”
和
“
组合
”
来实现。
继承概念的实现⽅式有两类:
实现继承:实现继承是指直接使⽤基类的属性和⽅法⽽⽆需额外编码的能⼒。
接⼝继承:接⼝继承是指仅使⽤属性和⽅法的名称、但是⼦类必需提供实现的能⼒。
所谓多态
就是向不同的对象发送同⼀个消息,不同对象在接收时会产⽣不同的⾏为(即⽅法)。即⼀个接⼝,可以实现多种
⽅法。
多态与⾮多态的实质区别就是函数地址是早绑定还是晚绑定的。如果函数的调⽤,在编译器编译期间就可以确定函
数的调⽤地址,并产⽣代码,则是静态的,即地址早绑定。⽽如果函数调⽤的地址不能在编译器期间确定,需要在
运⾏时才确定,这就属于晚绑定。
22
、多态的实现
多态其实⼀般就是指
继承加虚函数实现的多态
,对于᯿载来说,实际上基于的原理是,编译器为函数⽣成符号表时
的不同规则,᯿载只是⼀种语⾔特性,与多态⽆关,与⾯向对象也⽆关,但这⼜是
C++
中增加的新规则,所以也算
属于
C++
,所以如果⾮要说᯿载算是多态的⼀种,那就可以说:
多态可以分为静态多态和动态多态。
静态多态其实就是᯿载,因为静态多态是指在编译时期就决定了调⽤哪个函数,根据参数列表来决定;
动态多态是指通过⼦类᯿写⽗类的虚函数来实现的,因为是在运⾏期间决定调⽤的函数,所以称为动态多态,
⼀般情况下我们不区分这两个时所说的多态就是指动态多态。
动态多态的实现与虚函数表,虚函数指针相关。
扩展:
⼦类是否要᯿写⽗类的虚函数?⼦类继承⽗类时, ⽗类的纯虚函数必须᯿写,否则⼦类也是⼀个虚类不可实
例化。 定义纯虚函数是为了实现⼀个接⼝,起到⼀个规范的作⽤,规范继承这个类的程序员必须实现这个函数。