C++:布尔类型bool,函数重载、参数缺省值、哑元参数、内联函数、引用

来源:互联网 发布:淘宝自创品牌 编辑:程序博客网 时间:2024/05/29 00:34
<tips>
"$: nautilus ." 打开文件夹
"$: nautilus jy/c++" 打开指定路径的文件夹

一、布尔类型 bool (C++98 新增的基础数据类型)
bool 类型的变量有两个可能的值:1 / 0
bool 类型的常量有两个可能的值:true / false
bool 类型的变量占用的字节数,因系统不同而不同,大多数系统为 1 字节。
1. bool 类型的赋值:
把非 0 值赋值给布尔类型变量时,此变量值为真值(true)
把 0 值赋值给布尔类型变量时,此变量的值为假值(false)
bool b;int i = 100;b = i; // 1b = &i; // 1b = 'a'; // 1b = 3.14; // 1b = '\0'; // 0b = 0; // 0b = 0.0; // 0b = NULL; // 0
注:long double(12 btyes / 16 byte)


二、函数重载
1. 在C++中"函数可以同名",这种情况叫做 "函数重载"
2. 函数重载的定义:
在同一作用域内,相同的函数名,但参数个数或参数类型不同,构成重载。
/** 代码演示如下 **/#include <iostream>using namespace std;void foo() {    cout << "foo无参\n";}void foo(int i) {    cout << "foo(int)\n";}void foo(long int l) {    cout << "foo(long int)\n";}void foo(double d) {    cout << "foo(double)\n";}
int main() { //三个foo互为重载关系
    foo();
    foo(10);
    foo(10);
    foo(10L); //10L,10LL,10LLU(long, long long, unsigned long long)
    foo(10.0);
    return 0;
}


3. 函数重载的使用:
函数名 + 实参列表(来决定调用哪个函数)
4. 函数的返回值类型,不能区分函数是否重载
void foo(double d) {
    cout << "foo(double)\n";
}
double foo(double d) { //不够成重载,编译出现起义,编译不过
    cout << "foo(double)\n";
}
5. 重载的匹配规则
1)完全匹配 - 优先;
2)常量转换 - 次之;
3)升级转换 - 次之;//短字节到长字节
4)降级转换 - 次之;
5)省略号不定参转换;
/** 代码演示 **/#include <iostream>using namespace std;//以下两个函数示意升级转换 > 降级转换void foo(char c) {    cout << "foo(char)\n";}void foo(int i) {    cout << "foo(int)\n";}void foo(long int l) {    cout << "foo(long int)\n";}void foo(double d) {    cout << "foo(double)\n";}void bar(const char *p, char i) {    cout << "bar(const char *, char)\n";}void bar(char *p, double d) {    cout << "bar(char *, double)\n";}//以下两个函数示意降级转换 > 不定参转换void hum(char c, short s) {    cout << "hum(char, short)\n";}void hum(char c, ...) {    cout << "hum(char, ...)";}int main() {    hum('a', 1000000); //hum(char, short)    foo('a'); //foo(int)    char a[] = "hello";    bar(a, 'A'); //bar(const char *, char)    short s = 300;    foo(s);//foo(int)    return 0;}


6. 函数重载的原理
C++的函数的重载使用"函数的换名"来实现的。
可以用g++ -c编译出.o文件,nm filename.o 查看函数换名。
7. extern "C" 的作用:
告诉编译器由 extern "C"指定的函数,按照C语言的函数命名规则来调用编译(即不换名)。
用法有二:
1)加在函数名前;
extern "C" void foo() {...}
2)用 extern "C" { 多个函数声明 } 让多个函数都按着C语言的函数命名和调用规则来编译。"C/C++混合编程中使用"
#ifdef __cplusplus //与此预处理宏配合使用,C/C++可通用编译不出错extern "C" {  //gcc 和 g++均兼容,C中编译会去掉,C++编译会加上#endifvoid foo();void bar();int hum(int i, double d);...#ifdef __cplusplus}#endif
注:extern "C" 通常可预处理指令#ifdef __cplusplus 配合使用。


三、函数参数的缺省值(默认值)
规则:
1)默认值必须为字面值常量,或无名对象;
2)默认值的出现必须自右至左依次有默认值;
void foo(int a, int b = 10); //合法
void foo(int a = 10, int b = 100); //合法
void foo(int a = 10, int b); //不合法
void foo(int a, int b = 0, int c, int d = 0); //不合法
注意事项:
1. 实现了重载的函数,容易出现调用冲突;
void foo(int a, int b);
void foo(int a, int b, int c = 10);
foo(1, 2); //调用冲突
2. 如果一个函数有声明和实现分开,则默认参数应当加在声明处;
void foo(int a, int b, int c = 100); //声明处
void foo(int a, int b, int c) {...} //实现处
/** 代码演示如下 **/#include <iostream>using namespace std;double myadd(int a, double b, short c = 0, char d = '\0') {    return a+b+c+d;}int main() {    myadd(10, 3.14); //(10, 3.14, 0, '\0')    myadd(10, 3.14, 100); //(10, 3.14, 100, '\0')    cout << myadd(10, 20.0, 30, ' ') << endl; //(10, 20.0, 30, 32)    return 0;}


四、C++函数的哑元参数
/** 代码演示 **/#include <iostream>using namespace std;void func(int i, double) { // double处为哑元参数,C的无名形参    cout << "i=" << i << endl; // i=100}int main() {    func(100, 200);    return 0;}

作用:
1)兼容已经写好的程序,增强兼容性;
func(100, 3.14); //已经写好的函数调用
2)C++的++/--运算符重载时,用来区分前置和后置;
++i/i++, --i/i-- (后面补充)
哑元说明:
1)哑元可以带缺省参数,作用也是为了兼容性:
void listen(int = 0) {...}  //合法
listen(100); //100被忽略,编译能通过
listen(); //这么写也可以


五、内联函数 inline (C++98/C11支持内联)
1. 函数的调用过程
int getMax(int x, int y) {
return x > y ? x : y;
}
getMax(100, 200);
getMax函数的被调用过程示意如下:
1)向栈内压入一个空的返回值
| ret_value
2)把函数返回地址压入到栈内
| ret_value | ret_address
3)4)把 100,200 复制到栈顶
| ret_value | ret_address | 100 | 200
5)执行函数体内的代码
6)把返回值放到 ret_value
| 200 | ret_address | 100 | 200
7)弹出局部变量形参
8)将返回地址 ret_address --> PC
2. 内联函数的作用
告诉编译器如果在可能的情况下,把函数体的内部代码插入到调用的地方去编译,以去除函数压栈和弹栈的过程来提高程序的运行效率。
/** 代码演示 **/#include <iostream>using namespace std;inline int getMax(int x, int y) {    return x > y ? x : y;}int main() {    cout << (100 > 200 ? 100 : 200) << endl;    cout << getMax(100, 200) << endl;//inline的作用和上1行一样高效率    return 0;}

3. 内联的优缺点:
优点:减少了函数的传参和返回过程,提高了运行效率;
缺点:1)当一个比较大的函数被多次调用的时候,会造成调用函数的扩大
 2)内联不能递归调用。
4. 内联说明:
应用:"多次被调用的小而简单"的函数,适合内联。
注意:内联函数不能取地址(没有函数地址)。


六、C++的引用 reference
1. C语言访问变量的方法:"变量名,地址(指针)"
int i = 10;
int *pi = &i; // *pi 用指针来访问
2. C++提供了第三种访问变量的方法:"引用"
对象类型 & 引用对象的别名 = 对象名;
/** 代码演示 **/#include <iostream>using namespace std;int main() {    int i = 100;    int & ri = i; //ri为i的别名(引用)    cout << ri << " " << i << endl; //100 100    i++;    cout << ri << " " << i << endl; //101 101    ri++; //也是对变量i的操作    cout << ri << " " << i << endl; //102 102    return 0;}

3. 说明:
1)引用是对象的别名,通常不占用内存空间
2)引用"必须在定义的时候初始化"指向一个对象
指针可以有空指针,引用没有空引用。
int *p = NULL; //正确
int & p;  或  int & p = NULL; //都错误!!
3)引用在定义后,不能改变引用的对象,直至引用销毁,引用从一而终。
指针可以改变指向,引用不能改变指向。
int *p = &a;  p = &b; //正确
int & p = a;  p = b; //只是将b的值赋值给a,并没有改变p的指向
4)引用的类型必须和指向对象的类型一致。
int i = 100;
double & rd = i; //错误!!
5)具有非常属性的引用,不可以引用有常属性的对象;
int & rj = 200; //不合法
const double pi = 3.14; //定义
double & rpi = pi; //不合法,pi是有常属性的变量,只读变量
const double & crpi = pi; //合法
crpi = 7.8; //不合法
double & rd = i; //不合法
6)具有常属性的引用,可以引用非常属性的对象,也可以引用常属性的对象
int i = 100;
const int & cri = i;
i++; //合法
cout << cri << " " << i << endl; // 101 101
cri++; //不合法


4. 引用的实质:
引用的实质是'常量指针'。
int i = 100;
int * const pi = &i;
*pi //指针解引用运算符,或取值运算符
int & ri = i;
ri //C++的引用,相当于 int * const pi = &i;  ri <==> *pi
1)有指针的引用,但没有引用的指针
int i = 100;
int *p = &i;
int * & rp = p; //指针的引用,合法。
cout << rp << endl; //0xbf985b84 地址
char c = 'a';
char & rc = c;
char & * prc = &rc; //不合法,没有引用的指针!!
2)有指针的指针,没有引用的引用
char c = 'a';
char *pc = &c;
char **p = &pc; //指针的指针,二级指针
char & rc = c;
char && rrc = rc; //没有引用的引用,错误!!!
&& 这在C++11 标准中叫右值引用。


5. 引用作为函数的参数:
引用可以作为函数的参数进行传递。"函数传参"
/** 代码演示:交换两个值 **/#include <iostream>using namespace std;//传值void myswap1(int a, int b) {    int tmp = a;    a = b;    b = tmp;}void myswap2(int *pa, int *pb) {    int tmp = *pa;    *pa = *pb;    *pb = tmp;}void myswap3(int & ra, int & rb) { //类型必须相同    int tmp = ra;    ra = rb;    rb = tmp;}int main(void) {    int x = 100;    int y = 200;    myswap1(x, y);    cout << "x=" << x << " " << "y=" << y << endl;//100 200    myswap2(&x, &y); //第一次交换成功    cout << "x=" << x << " " << "y=" << y << endl;//200 100    myswap3(x, y);  //第二次交换成功,直接变量做实参    cout << "x=" << x << " " << "y=" << y << endl;//100 200    return 0;}


6. 引用作为函数的返回值:
1)不能返回局部对象的引用;(这点和指针类似)
2)多数传引用的目的是为了减少对象的复制次数,提高运行效率。
/** 代码演示 **/#include <iostream>using namespace std;int getmax1(int a, int b) {    return a > b ? a : b;}static int s_max = 0;int & getmax2(int a, int b) { //会少一次返回值这个值的复制    s_max = a > b ? a : b;    return s_max;//  return a > b ? a : b; //返回局部对象的引用,野引用,不能出现!!}int & getmax3(int & a, int & b) { //没有任何一个参数的复制,仅需传值    return a > b ? a : b;}int main(void) {    int x = 100;    int y = 200;    cout << getmax1(x, y) << endl; //200    cout << getmax2(x, y) << endl; //200    cout << s_max << endl; //200    int & rmax = getmax2(x, y);    cout << rmax << endl; //200    s_max++; //验证rmax是s_max的引用    cout << rmax << endl; //201    rmax = 500;    cout << s_max << endl;    int m = getmax2(x, y); //会多一次复制,复制1份返回值赋值给m    int & rm = m;    cout << rm << endl;    cout << "getmax3= " << getmax3(x, y) << endl;    return 0;}


练习作业:使用引用参数完成两个字符串指针(const char *)的交换
#include <iostream>using namespace std;void myswap(const char *& str1, const char *& str2) {    const char *tmp = str1;    str1 = str2;    str2 = tmp;}int main() {    const char * s1 = "hello";    const char * s2 = "world";    cout << "s1 = " << s1 << endl; //hello    cout << "s2 = " << s2 << endl; //world    myswap(s1, s2);    cout << "交换后:" << endl;    cout << "s1 = " << s1 << endl; //world    cout << "s2 = " << s2 << endl; //hello    return 0;}

七、操作符别名
{ <%
} %>
[ <:
] :>
# %:
! not
!= not_eq
& bitand
八、引用的扩展
1. 数组的引用
int arr[5] = {1, 2, 3, 4, 5};
int (& rarr)[5] = arr; //sizeof(rarr) = 20
2. 函数的引用
int mymax(int x, int y) {
return x > y ? x : y;
}

int (& rmax)(int, int) = mymax;


0 0
原创粉丝点击