六 C++的bool类型
1 bool类型是C++中的基本数据类型,专门表示逻辑值:true、false
2 bool类型内存上占一个字节:1表示true,0表示false
3 bool类型变量,可以接受任意表达式的结果,但不保存表达式的结果,其值非零则为true,零则为false
//使用流控制符,打印bool类型变量的结果时,以字符串输出
cout << boolalpha << flag_bool << endl;
#include <iostream>
using namespace std;
int fun(void){
return 1;
}
int main(void){
bool flag_bool = false;
flag_bool = fun();
cout << "size = "<< sizeof(flag_bool) << ",value = "
//使用流控制符,打印bool类型变量的结果时,以字符串输出
<< boolalpha << flag_bool << endl;
return 0;
}
七 操作符别名
&& <–> and
|| <–> or
{ <–> <%
} <–> %>
! <–> not
…….
八 C++的函数
1、 函数重载
eg: 图形库,包含很多绘图库
用C实现:
//绘制矩形的函数
void draw1(int x,int y,int w,int h){…}
//绘制圆形的函数
void draw2(int x,int y,int r){…}
——————————
用c++实现:
//绘制矩形的函数
void draw(int x,int y,int w,int h){…}
//绘制圆形的函数
void draw(int x,int y,int r){…}
1) 函数重载的定义:
在相同作用域,可以定义同名的函数,但是它们的参数必须有所区分,这样的函数构成重载关系。
注:函数重载和返回类型无关,与形参名字无关,参数的区别值的是形参个数,类型,顺序的不同
2) 函数重载匹配
调用重载关系的函数时,编译器根据实参与形参的匹配程度,自动选择最优的重载版本。
g++一般的匹配规则:
完全匹配 >= 常量转换 > 升级转换 > 降级转换 > 省略号匹配(不定长参数)
3) 函数重载的原理
g++的编译器在编译一个源文件的时候,会将源文件中函数名的标识符进行替换,要把函数的参数表整合到新的函数名中。这就导致了源文件中函数名称一样,形参列表不同的函数,在编译的时候,不会发生重定义的报错。因为在编译的最后过程中,根本就不存在同名函数。
4) c调用c++的函数
extern “C” void hello(void){};
当c调用c++函数的时候,使用上述的语句对一个c++函数进行声明,告知c++编译器,按照c的方式编译该函数,不要对该函数进行换名。
注:extern “C”声明之后的函数,不能进行重载。
扩展:
extern “C”{
void fun1(…){…}
void fun2(…){…}
…
}
2、 函数的缺省参数(默认的实参)
1) 可以为函数的部分参数或全部参数指定缺省值,调用该函数时,如果不给实参,就取缺省值作为相应参数的实参
void func(int a,int b = 20){}
2) 缺省参数必须靠右,如果一个参数有缺省值,那么这个参数的右边的所有参数都必须带有缺省值。
3) 如果函数的定义和声明分开,缺省参数应该写在函数的声明部分,而定义部分不写。
3、 C++函数的哑元参数
1) 在函数定义的时候,只有类型而没有变量名的形式参数成为哑元
void func(int/哑元/,…){…} //函数实现中是无法使用这个哑元
2) 使用哑元的场景
–> 兼容旧代码
eg:
//算法函数
void math_func(int a,int c,int b){…}
//使用者
int main(void){
math_func(1,2,3);
math_func(1,2,3);
math_func(1,2,3);
math_func(1,2,3);
}
——————————————
//算法函数
void math_func(int a,int,int){…}
–>操作附重载:区分前后++,–(重载)
4、 内联函数(inline)
1) 定义
使用inline关键字修饰一个函数,表示该函数是内联函数,编译器将会尝试做内联优化,避免函数调用的开销。
inline void func(){…}
2) 适用场景
–>多次调用的小而简单的函数适合内联
–>调用次数少或者大而复杂的函数,不适合内联
–>递归函数不适合内联
注:内联对编译器只是一种建议,不是强制要求,有些函数不加inline关键字也会默认处理为内联优化,有些函数即便加了inline也会被编译器忽略掉。
注:在C语言中也有内联,但是不在标准C中
九 C++的动态内存分配
1、 回顾C中的动态内存分配
1) 分配:malloc()
2) 释放:free()
3) 错误处理:返回值
2、 C++中使用new/delet操作附管理动态内存
1) 内存分配:new/new[]
2) 内存释放:delet/delet[]
3) 错误处理:C++异常处理
eg:
//动态分配一块内存,保存一个整型数:123
//C实现
int p_i = (int )malloc(sizeof(int));
*p_i = 123;
…
free(p_i);
p_i = NULL;
———————————————–
//C++实现
/*
int *p_i = new int;
*p_i = 123;
*/
int *p_i = new int(123);
…
delet p_i;
p_i = NULL;
———————————————–
eg: 分配一块内存,保存5个整型数 1 2 3 4 5
//C实现
int * parr = (int *)malloc(5*sizeof(int));
for(int i = 0; i < 5;i++)
*(parr+i) = i + 1;
free(parr);
//C++实现
**int *parr = new int[5]{9,2,3,5,7};**
delet[] parr;
parr = NULL;
十 C++的引用
1、定义
1) 引用就是某个别名的别名,对引用的操作和对该变量本身完全相同。
类型 &引用 = 变量名;
注:引用在定义时,必须要绑定一个变量,也就是必须要初始化,而且初始化以后其绑定的目标不能再修改。
注:引用的类型与其绑定目标变量类型要一致。
eg:
int a = 100;
int &b = a;//b是a的引用(别名)
b = 1000;
cout << a << endl 注:引用的类型与其绑定目标变量类型要一致。
2、 常引用
1) 定义时加const关键字,即为长引用,不能通过常引用直接修改引用的目标
const 类型 &引用 = 变量名;
eg:
int a = 1000;
const int &b = a;
//int cosnt &b = a;
2) 普通的引用也可以叫做左值引用;常引用也叫万能引用,既可以引用左值也可以引用右值;
左值:可以放在赋值操作符左侧,可以被修改;
右值:只能放在赋值操作符右边,不可以被修改;
eg:
int& ref = 100;//报错
const int &ref = 100;
左值:
非左值:字面量(除了字符串),多项表达式
左值引用:typename &引用 = 左值,引用必须在声明时初始化,引用的类型必须和左值的类型一致。
const引用:const typename &引用 = 对象,也是必须在声明时初始化,但却不要求对象是左值,甚至可以是一个字面值或者表达式,在一定程度上可以接受不同类型的对象
const引用,存在一种叫做临时变量的机制,需要满足以下两种条件:
1、对象和引用的类型相同,但不是左值
2、对象和引用的类型不同,但可以转换
临时变量机制:当一个const引用的对象满足上述的其中之一的条件,编译器会把为对象创建一个临时变量,这个临时变量变的类型与引用一致。引用将会指向这个临时变量,而不是指向对象本身。
验证如下:
int main(void){
//一个int类型的变量
int num = 2;
//用const double 类型的引用
const double &renum = num;
//打印它们的地址
cout << "&num = " << &num << endl;
cout << "&renum = " << &renum << endl;
return 0;
}
--------------------------------------
&num = 0x7fff410252f4
&renum = 0x7fff410252f8
const的临时变量机制,有点类似于按值传递时,高级基础类型对低级基础类型的兼容(隐式类型转换)。让const引用的兼容性更强。当然,这种兼容性在基础类型中是很容易被体现的。但是,引用机制是为了对象和结构体在函数之间传递而设计出来的,所以这种特性很难被用上,除非两个结构体之间存在可以转换的关系,目前为止,还没有听过可以互相转换的结构体。所以const引用,还是理解为不可修改引用的意思,会比较好