内联函数的大致流程
内联函数不同于不同的函数,一般的函数都有自己的内存地址,程序调用的时候首先访问函数的地址然后在调用函数、而内联函数则是采用代码块的复用。如下图
内联函数适用于代码量小的函数,递归函数不能内敛。
内敛与宏
宏不是通过参数传递来实现的,而是通过文本替换
#define SQUARE(x) x*x
a=SQUARE(5); is replace by a=5.0*5.0
引用变量
引用变量必须在声明时赋予初始值,一旦与某个变量关联起来就必须效忠于他 也就是说
1 | int * const pr=&rate; |
也就是说
1 | int a=1; |
执行这段代码后c还是指向a;
临时变量、引用参数与const
1 | double recube(const int & a) |
这时所有的类型都可以通过构建临时对象的方式来通过编译,但是如果将里面的const去除
1 | double recube( int & a) |
则只能通过int &或者int 的变量,无法通过构筑临时变量的方式来传递参数。
尽可能的使用const
使用const的理由有三个
使用const可以避免无意的修改
使用const可以使函数获得const参数和字面值
使用const能正确生成和使用临时对象
关于返回const by refrence
返回的如果是引用的话,则此时返回值是一个左值,返回的是普通值的话就为一右值。这样这样的代码就会成立
1 | double & recube(const int & a) |
为了防止这种傻逼行为的发生,我们将返回refrence的函数给返回const
函数重载
函数重载返回值可以不同但特征标必须不同,如果有两个版本的函数能通过显示转换被调用,则这两个版本不能同时存在。
类中const函数与非const函数也构成函数重载
右值引用
C++11新标准,可以让一个引用指向运算结果一个运算结果,例如
1 | int&& a=3+4; |
这样以下的重载中会调用如下的右值版本
1 | double x=55.5; |
如果没有定义stov(double&& )的话,将通过转化调用stove(const double &)
函数模板
- 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及他们的重载版本
- 显示具体化的原型和定义应该以template<>大头
- 具体化优先于常规模板而非模板函数优先于模板函数和具体化
编译器将选择那个函数版本
有如下代码
1 | may('B'); |
以下面的顺序进行匹配
- 完全匹配 但是常规函数优先于模板
- 提升转化
- 标准转换
- 用户定义的转换
关于提升转换与标准转换
有五种类型的标准转换,如下:A、从任何整数类型或枚举类型到其他整数类型(除了提升) B、从任何浮点类型到其他浮点类型(除了提升转换)C、从任何整数类型到浮点类型,或者反之D、整数0到指针类型、任何指针类型到 void 指针类型E、从任何整数类型、浮点类型、枚举类型、指针类型到bool
这样就可以选择为函数 #3和函数# 5
完全匹配与最佳匹配
下图展示了完全匹配允许的无关紧要的转换
类型模式与名称空间
头文件中应该包含一下的内容
- 函数原型
- 使用#define和const定义的符号常量
- 结构的声明
- 类的声明
- 模板的声明
- 内联函数
C++使用四种方案来存储数据
- 自动存储的:在函数内声明的
- 静态存储,C++共有三种静态变量
- 线程存储:使用关键字thread_local声明的变量、其周期与所属的线程一样长
- 动态存储的: new和delete相关内容见另一篇博文 C++内存管理——从平地到万丈高楼
静态持续变量
与C一样C++提够了三种静态持续连接性,外部链接、内部链接、无连接。三种连接性都在整个程序执行期间都存在。另外如果没有显式初始化静态变量,则默认为0。
1 | int gloab=1; //外部静态 |
count变量只在fun1函数中才能被调用,且在每次的调用中count都是同一块内存。one_file变量只在这个文件中才被调用,gloab变量在整个程序中都能被调用。
表9.1显示了引入名称空间之前的变量存储特性。
extern 关键字
由于编译器只允许一次声明,所以在每次使用的同一个外部变量时需要加上extern 关键字。例如下例
1 | //源文件1 |
但是如果不是const变量时,可以只在定义的地方加上extern
1 | //源文件1 |
注意: 只需要一份赋值即可
名称空间
名称空间对外部是公开的,也就是说可以在任意的代码块中可以添加内容
1 | namespace Jill |
在Jill中添加Jill函数属性。
现在的类库函数库的设计都是采用了名称空间的设计模式例如从math采用的是_CSTD的namespace在yvals.c的文件下
类与对象
转换函数
在类中有以下的声明,就说明声明了转换函数
1 | operator typename(); |
还是typename可以是内置类型,也可以是自定义类型
转换函数应注意下面几点要求
- 转换函数必须是类方法
- 抓换函数不能指定函数类型
- 转化函数不能带参数
编写实现时可以参数强制类型转化来实现,调用时以下方式调用
1 | class A |
类的动态分配
类中函数
类中只能定义一个默认构造函数
拷贝构造函数
按值传递意味着船舰原始变量的一个副本,编译器采用拷贝构造函数生成临时的变量。具体来时当函数通过值传递或者没有返回值不是引用的时候,都将调用拷贝构造函数。而有些编译器会将类的操作结果赋予一个临时对象,此时会调用拷贝构造函数。总之,若有对象初始化另一个对象,就会调用拷贝构造函数。