(1)使用inline修饰函数的声明或实现, 可以使其变成内联函数.
(2)建议声明和实现都增加inline修饰
特点:
(1)编译器会将函数调用直接展开为函数体代码, 就不存在函数调用了.
代价:会增加代码数量, 使代码变臃肿.
但是如果不使用内联函数的话, 由于在函数调用过程中, 会先开辟栈空间给函数, 然后执行函数内的代码, 最后回收栈空间.存在这样一个操作, 如果这个函数频繁调用的话, 就会频繁进行这个操作, 使效率变低.
所以什么时候使用内联函数?
1.函数代码体积不大
2.频繁调用函数
(2)可以减少函数调用的开销
(3)会增大代码体积
注意:
(1)尽量不要内联超过10行代码的函数
(2)有些函数即使声明为inline, 也不一定会被编译器内联, 比如递归函数(无法内联).
(1) 内联函数和宏, 都可以减少函数调用的开销.
(2)对比宏, 内联函数多了语法检测和函数特性.
(1)const修饰的变量必须在定义时就指明它的值.
(2)如果修饰的是类或结构体(的指针), 其成员也不可以更改.
注意: 在C语言中定义结构体变量struct Date d = {2019,1,2};
但在C++里定义结构体变量时, 不需要struct, 可以直接Date d = {2010,2,2};
(3)
(1)在C语言中, 使用指针(Pointer)可以间接获取, 修改某个变量的值
(2)在C++中, 使用引用(Reference)可以起到跟指针类似的功能.
#include
using namespace std;
int main()
{
int age = 10;
// 定义了一个age的引用, refAge相当于是age 的别名
int &refAge = age;
refAge = 20;
cout << age << endl;
// 结果是20
return 0;
}
注意点:
(1)引用相当于是变量的别名(基本数据类型, 枚举, 结构体, 类, 指针, 数组等, 都可以有引用)
(2)对引用做计算, 就是对引用所指向的变量做计算.
(3)在定义的时候就必须初始化, 一旦指向了某个变量, 就不可以再改变, "从一而终"
(4)可以利用引用初始化另一个引用, 相当于某 个变量的多个别名.
(5)
(6)默认情况下引用类型要跟引用的变量类型匹配
引用存在的价值之一:比指针更安全, 函数返回值可以被赋值.
(1)引用的本质就是指针, 只是编译器削弱了它的功能, 所以引用就是弱化了的指针.
x86: 32位 指针4个字节
x64: 64位 指针8个字节
(2)一个引用占用一个指针的大小
学习汇编语言2大知识点:
1.汇编指令
2.寄存器
C++可以轻易反汇编, 可以马上知道所写的C++代码的本质是什么.而其他的语言不容易看到.
汇编语言种类:
(1)8086汇编(16bit)
(2)x86汇编(32bit)
(3)x64汇编(64bit), 目前都是
(4)ARM汇编(嵌入式, 移动设备)
x64汇编根据编译器的不同, 有2种书写格式
(1)intel VS
(2)AT&T GCC, MAC
汇编语言不区分大小写
mov eax, 10
MOV EAX, 10
等价
不同的架构, 寄存器不一样
RAX\RBX\RCX\RDX : 通用寄存器
x86 32位一个寄存器能存4个字节
x64 一个寄存器能存8个字节
x64汇编兼容以前的汇编,(兼容以前的寄存器).
所以在RAX的低四个字节是EAX寄存器, EAX的低2个字节是AX寄存器, AX又分为AH和AL
AH H high AX的高位
AL L low AX的低位
**结论:**所以如果给RAX赋8个字节的值(例如:1122334455667788), 会把原来赋值给EAX的值覆盖成55667788, 并把AX原来的值覆盖成7788.
x86 环境下(32位)
EAX\EBX\ECX\EDX : 通用寄存器
8086(16位)
AX\BX\CX\DX\ : 通用寄存器
一般的规律:
R开头的寄存器是64bit的, 占8个字节
E开头的寄存器是32bit的, 占4个字节
(1)mov dest, src
将src的内容赋值给dest, 类似与dest = src
(2)[地址值]
中括号[]里面放的都是内存地址
word 是 2 字节, dword 是 4 字节(double word), qword是8字节(quad word)
int a = 4;
对应汇编:mov dword ptr [ebp-xxh] 4
ptr是固定写法, ebp-xxh是a的地址,dword说明是4个字节, 所以会把ebp-xxh往高地址的包括ebp-xxh的4个内存地址赋值成4
(3)call 函数地址
一旦看到call 一定是调用函数
call之前的push都是传参
(4)变量地址总结
一个变量的地址值, 是它所有字节地址中的最小值.
例: int a = 4;
a有4个字节, 那每一个字节都有一个内存地址.
所以它所有字节地址中的最小值就是变量a 的地址值.
&a 的值是0x007DF968
大小端模式, 现在大部分都是小端模式.
小端模式:
4的二进制00000000 00000000 00000000 00000011
存储时:高字节对应高地址,低字节对应低地址
所以内存地址 内容
0x7DF968 00000011
0x7DF969 00000000
0x7DF96A 00000000
0x7DF96B 00000000
读取时:从高地址读取所以读取00000000 00000000 00000000 00000011
(5)lea dest, [地址值]
lea : load effect address 装载一个有效的地址值
lea eax, [1122H]
意思:直接将地址值赋值给eax
如果是mov eax, [1122H]
意思是:取出1122H这个地址存放的值再赋值给eax.
(6)ret
ret: return
函数返回
(7)xor op1, op2
将op1和op2异或的结果赋值给op1, 类似与op1 = op1 ^ op2
(8)add op1, op2
类似于op1 = op1 + op2
(9)sub op1, op2
类似于op1 = op1 - op2
(10)inc op
inc : increase
自增, 类似于 op = op + 1
(11)dec op
dec : decrease
自减, 类似于op = op - 1
(12)jmp 内存地址
jmp : jump 跳转
调转到这个内存地址对应的代码
j开头的一般都是跳转, 大多数是带条件的跳转, 一般跟test, cmp等指令配合使用.
(13)jne :jump not equal, 比较结果不相等才跳转.
其他j开头的汇编指令详见jcc(Jump Condition Code)文件
引用可以被const修饰, 这样就无法通过引用修改数据了, 可以称为常引用.
(1)const int &ref = age;
ref = 30; // 错误
可以访问
类似于 const int *ref = &age;
(2)int & const ref = age;
ref = 30; // 正确
意思是ref不能修改指向, 但是可以通过ref间接修改所指向的变量
但没有意义, 因为ref本来就不能修改指向.
所以const 必须写在&的左边, 才能算是常引用.
(1)可以指向临时数据(常量, 表达式, 函数返回值等)
(2)可以指向不同类型的数据.
(3)作为函数参数时(此规则也适用于const指针)
1.可以接受const和非const实参(非const引用, 只能接受非const实参)
#include
using namespace std;
int sum(const int &v1,const int &v2) {
return v1 + v2;
}
int main()
{
// 非const实参
int a = 10;
int b = 20;
sum(a, b);
// const实参
const int c = 10;
const int d = 20;
sum(c, d);
sum(10, 20);
return 0;
}
因为如果非const引用可以接受const实参的话, 在函数里面可以v1 = 20; 这样就会改变c的值, 但c是const的常量, 所以会冲突矛盾.
2.可以跟非const引用构成重载.
int sum(int &v1, int &v2) {
}
int sum(const int &v1, const int &v2) {
}
如果不是引用时,就不能构成重载.
int sum(int v1, int v2) {
}
int sum(const int v1, const int v2) {
}
// 不行
补充:当常引用指向了不同类型的数据时, 会产生临时变量, 即引用指向的并不是初始化时的那个变量.
(1)
int arr[] = {1,2,3};
int (&ref)[3] = arr;
ref[1] = 10;
类似于0
int arr[] = {1,2,3};
int (*p)[3] = arr;
p[1] = 10;
(2)
int arr[] = {1,2,3};
int * const &ref = arr;
因为数组名arr其实是数组的地址, 也是数组首元素的地址
数组名arr可以看做是指向数组首元素的指针.(int *类型), 又因为数组的地址不能修改是常量
所以可以写成, int * const &ref = arr; 常引用
其他C++系列文章:
C++知识点总结(基础语法1-函数重载, 默认参数)
C++知识点总结(基础语法2-内联函数, const, 引用)
C++知识点总结(面向对象1-类和对象, this指针, 内存布局)
C++知识点总结(面向对象2-构造函数, 初始化列表)C++知识点总结(面向对象3-多态)
C++知识点总结(面向对象4-多继承, 静态成员static)
C++知识点总结(面向对象5-const成员, 拷贝构造函数)
C++知识点总结(面向对象6-隐式构造, 友元, 内部类, 局部类)
C++知识点总结(其他语法1-运算符重载)
C++知识点总结(其他语法2-模板, 类型转换, C++11新特性)