目录二
六.C++布尔类型(bool)
①bool类型在C++中是基本的数据类型,专门表示逻辑值,逻辑真用true表示,如果逻辑假false。
②bool类型在内存上占一个字节:数值1表示true,数值0表示false
③bool类型的变量可以接收任意类型表达式结果,结果非零则为true,为零则为false
eg.
#include <iostream>
using namespace std;
int main(void){
bool b = false;
cout << "size=" << sizeof(b) << endl;
cout << "b=" << b << endl;
b = 3 + 5;
cout << "b=" << b << endl;//1
b = 1.2 * 3.4;
cout << "b=" << b << endl;//1
char* p = NULL;//NULL-->(void*)0
b = p;
cout << "b=" << b << endl;//0
return 0;
}
七.操作符别名(了解)
&& <==> and
|| <==> or
^ <==> xor
{ <==> <%
} <==> %>
......
eg.
#include <iostream>
using namespace std;
int main(void)
<%
int i = 0;
int j = 1;
if(i or j)<%
cout << "true" << endl;
%>
else <%
cout << "false" << endl;
%>
return 0;
%>
八.C++的函数
1.函数重载(overload)
①定义
在相同作用域,定义的同名函数,但是它们的参数必须有所区分,这样的函数将构成重载关系。
(注:函数能否重载和返回类型无关)
eg.
#include <iostream>
using namespace std;
void func(int i){
cout << "func(int)" << endl;
}
void func(int a,int b){
cout << "func(int,int)" << endl;
}
//double func(int i,int j){}//error
void func(int a,float b){
cout << "func(int,float)" << endl;
}
int main(void){
func(10);
func(10,20);
func(10,1.23f);
//函数指针的类型决定匹配的重载版本
void (*pfunc)(int,float) = func;
pfunc(10,20);//func(int,float)
return 0;
}
②函数重载匹配
调用重载关系的函数时,编译器会根据实参与形参的匹配程度,自动选择最优匹配版本,比如g++编译器匹配一般规则:
完全匹配>=常量转换>升级转换>降级转换>省略号匹配
eg.
#include <iostream>
using namespace std;
//char->int:升级转换
void bar(int i){
cout << "bar(1)" << endl;
}
//char->const char:常量转换
void bar(const char c){
cout << "bar(2)" << endl;
}
//short->char:降级转换
void fun(char c){
cout << "fun(1)" << endl;
}
//short->int:升级转换
void fun(int i){
cout << "fun(2)" << endl;
}
//省略号匹配
void hum(int i,...){
cout << "hum(1)" << endl;
}
//double->int:降级转换
void hum(int i,int j){
cout << "hum(2)" << endl;
}
int main(void){
char c = 'a';
bar(c);
short s = 10;
fun(s);
hum(10,1.23);
return 0;
}
③函数重载原理
C++编译器是通过对函数进行换名,将参数表的类型整合到新的函数名中,解决函数重载和名字冲突的矛盾。
笔试题:C++中 extern “C” 声明的作用?
可以在函数声明前面加入extern “C”,要求C++编译器不对该函数进行换名,便于C程序直接调用该函数.
(注:被 extern “C” 声明的函数无法重载)
2.哑元参数
①定义
定义函数时,只有类型而没有变量名形参成为哑元.
void func(int /*哑元*/){
...
}
②使用哑元场景
–》在操作符重载,区分前后++、–
–》为了兼容以前的旧代码
eg.
算法库:void math_func(int a,int b){...}
使用者:
int main(void){
math_func(10,20);
...
math_func(30,40);
}
-----------------------------------------------
升级算法库:void math_func(int a,int/*哑元*/){...}
使用者:
int main(void){
math_func(10,20);
...
math_func(30,40);
}
3.缺省参数(默认实参)
①定义
可以为函数的部分参数或全部参数指定缺省值,调用该函数时,如果不给实参,就取缺省值作为默认实参。
void func(int a,int b,int flag=0/*缺省参数*/){}
②靠右原则,如果函数的一个参数有缺省值,那么该参数右侧的所有参数都必须带有缺省值。
③如果函数的定义和声明分开,缺省参数应该是写在函数的声明部分,而定义部分不写。
void func(...);//函数声明
void func(...){...}//函数定义
eg.
#include <iostream>
using namespace std;
//函数声明
void func(int a,int b = 20,int c = 30);
//void func(int i){}//歧义错误
int main(void){
func(11,22,33);//11 22 33
func(11,22);//11 22 30
func(11);//11 20 30
return 0;
}
//函数定义
void func(int a,int b/*=20*/,int c/*=30*/){
cout << "a=" << a << ",b=" << b << ",c="
<< c << endl;
}
4.内联函数(inline)
①定义
使用inline关键字修饰的函数即为内联函数,编译器将会尝试进行内联优化,可以避免函数调用的开销,提高代码执行效率。
inline void func(void){}//内联函数
(理解:正常程序运行时,调用函数这个过程会消耗时间;若使用内联函数,则把要调用的函数直接放到原有程序中,这样就减少了调用的时间,但相应的也就增加了内存。)
②使用说明
–》多次调用的,小而简单的函数适合内联
–》调用次数极少或大而复杂的函数不适合内联
–》递归函数不能内联优化
–》虚函数不能内联优化
(注:内联函数只是一种建议而不是强制要求,能否进行内联优化是由编译器决定的,有些函数不加inline修饰也会默认处理为内联优化,而有些函数即便加了inline修饰也会被编译器忽略掉。)
九.C++动态内存管理
1.C语言动态内存管理
①分配:malloc()
②释放:free()
2.C++动态内存管理
①分配:new/new[]
②释放:delete/delete[]
eg.1
#include <iostream>
using namespace std;
int main(void){
//int* pi = (int*)malloc(4); C语言
int* pi = new int; //C++
*pi = 123;
cout << *pi << endl;
//free(pi);//C语言
delete pi;//C++
pi = NULL;//防止野指针
//动态分配内存同时初始化
int* pi2 = new int(321);
cout << *pi2 << endl;//321
(*pi2)++;
cout << *pi2 << endl;//322
delete pi2;
pi2 = NULL;
return 0;
}
eg.2
#include <iostream>
using namespace std;
int main(void){
//new内存保存多个数据(new数组)
int* parr = new int[10];
for(int i=0;i<10;i++){
//*(parr+i) = i+1
parr[i] = i+1;
cout << parr[i] << ' ';
}
cout << endl;
delete[] parr;
parr = NULL;
//new数组同时初始化,C++11标准支持
int* parr2=new int[10]{9,8,7,6,5,4,3,2,1,0};
for(int i=0;i<10;i++){
cout << parr2[i] << ' ';
}
cout << endl;
delete[] parr2;
parr2 = NULL;
return 0;
}
eg.3
#include <iostream>
using namespace std;
int main(void){
//int* p1;
//delete p1;//delete野指针危险
int* p2 = NULL;
delete p2;//delete空指针安全,但是没有意义
int* p3 = new int;
delete p3;
//delete p3;//不能连续delete同一个指针
return 0;
}
十.C++的引用(Reference)
1.定义
①引用即别名,就是某个变量的别名,对引用别名的操作与对变量本身完全相同.
(就相当于两个变量名指向了同一个内存地址,一个被修改,另一个也跟着修改。)
②语法规则
类型 & 引用名 = 变量名;
eg.int& b = a;//b引用a,b就是a的别名
注:引用在定义时必须初始化,初始化以后绑定的目标不能再改变。
注:引用的类型与绑定的目标变量类型要相同。
eg.
#include <iostream>
using namespace std;
int main(void){
int a = 10;
int& b = a;//b引用a,b就是a的别名
cout << "a=" << a << ",b=" << b << endl;
cout << "&a=" << &a << ",&b=" << &b << endl;
b++;//a++
cout << "a=" << a << ",b=" << b << endl;
//引用在定义时必须初始化
//int& c;//error
int d = 20;
b = d;//ok,但不是修改引用目标,仅是赋值操作
cout << "a=" << a << ",b=" << b << endl;
cout << "&a=" << &a << ",&b=" << &b << endl;
//引用类型和目标变量类型要一致
char& r = d;//error
return 0;
}
2.常引用
①定义引用时加const修饰,即为常引用,不能通过常引用修改引用的目标。
const 类型 & 引用名 = 变量名;
类型 const & 引用名 = 变量名;//和上面完全等价
eg:
int a = 10;
const int& b = a;//b是a的常引用
b++;//error
a++;//ok,此时a和b的值都为11
②普通引用也可以叫做左值引用,只能引用左值;而常引用也可以叫做万能引用,既可以引用左值,也可以引用右值。
③关注左值和右值
左值(lvalue):可以放在赋值操作符左侧,可以被修改.
--》普通变量
--》前缀++、--
--》赋值表达式结果
右值(rvalue):只能放在赋值操作符右侧,不可以被修改,引用时要加const,常引用
--》字面值常量
--》类型转换结果的临时变量
--》加法(大多数、后++、--)表达式结果的临时变量
--》函数中返回的临时变量
eg.
#include <iostream>
using namespace std;
int func(void) {
int num = 100;
cout << "&num=" << &num << endl;
return num;
}
int main(void) {
//int& r1 = 100;//error
const int& r1 = 100;//ok
cout << r1 << endl;
char c = 'a';
//首先要c转换为int类型,转换结果将保存到
//临时变量,r2实际要引用是临时变量(右值)
//int& r2 = (int)c;//error
const int& r2 = (int)c;//ok,此时c相当于是常数了,所以引用的话要加const
cout << "&r2=" << &r2 << endl;
cout << "&c=" << (void*)&c << "\n" << endl;
int a = 10;
int b = 20;
//加法表达式结果是临时变量(右值)
//int& r3 = a+b; error
const int& r3 = a + b;
cout << r3 << endl;//30
int& r4 = ++a;//ok
cout << r4 << endl;//11
cout << &a << ',' << &r4 << endl; //地址相同
int& r5 = (a += b);
cout << r5 << ',' << a << endl;
cout << &r5 << ',' << &a << endl;
//函数返回结果不是return的num,而是return时生成的临时变量(右值)
//int& r6 = func();//error
const int& r6 = func();//ok
cout << "\n" ;
cout << r6 << endl;//100
cout << "&r6=" << &r6 << endl;
return 0;
}