Day37、函数重载、缺省参数、哑元参数、内联函数inline、内存分配、引用
来源:互联网 发布:网络点播系统 编辑:程序博客网 时间:2024/05/29 11:00
一、 C++函数
1、 函数重载
例:图形库画图函数
C:
画圆形:drawCircle(int x,int y,double r){……}
画矩形:drawRect(int x,int y,double w, double h){….}
C++:
画圆形:draw (int x,int y,double r){……}
画矩形:draw (int x,int y,double w, double h){….}
函数相同,参数不同
1) 定义:
在相同的作用域,定义同名的函数,但是它们的参数表必须有所区分,这样函数构造重载关系。
注:函数重载和返回类型无关,与参数名无关
2) 函数重载匹配:
调用重载关系的函数时,编译器将根据实参与形参的匹配程度,自动选择最优的匹配版本
例:
1 #include<iostream>
2 using namespace std;
3 int foo(int a){
4 cout<<"foo(int)"<<endl;
5 }
6 void foo(int a,int b){
7 cout<<"foo(int,int)"<<endl;
8 }
9 void foo(void){
10 cout<<"foo(void)"<<endl;
11 }
12 //void foo(int b,int a){ } 无法重载
13 void foo(int a,float b){
14 cout<<"foo(int ,float)"<<endl;
15 }
16 int foo(float b,int a){
17 cout<<"foo(float,int)"<<endl;
18 }
19 int main(){
20 foo();
21 foo(10);
22 foo(10,20);
23 // foo(10,3.14); 3.14是double类型,小数默认为双精度
24 foo(10,3.14f); //匹配foo(int,float)
25 /*
26 一个函数指针调用重载函数,由函数指针类型决定,而不由实参决定
27 */
28 void (*pfunc)(int,float)=foo;//函数指针
29 pfunc(10,20)
30 return 0;
31 }
foo(void)
foo(int)
foo(int,int)
foo(int ,float)
对于g++ v4.4.7编译器的一般匹配规则:
完全匹配>常量匹配>升级转换>降级转换>省略号匹配
1 #include<iostream>
2 using namespace std;
3 //升级转换:char--->int
4 void bar(int i){
5 cout<<"bar(1)"<<endl;
6 }
7 //常量转换:char-->const char
8 void bar(const char c){
9 cout<<"bar(2)"<<endl;
10 }
11 //降级转换:short-->char 不安全
12 void func(char c){
13 cout<<"func(1)"<<endl;
14 }
15 //升级转换:short-->int 安全
16 void func(int i){
17 cout<<"func(2)"<<endl;
18 }
19 //过分的升级转换short-->long long
20 void func(long long ll){
21 cout<<"func(3)"<<endl;
22 }
23 //不定长参数:可以接受任意多个任意长度的参数,类似printf
24 //省略号匹配(最差)
25 void hum(int i,...){
26 cout<<"hum(1)"<<endl;
27 }
28 //降级转换:double-->int
29 void hum(int i,int j){
30 cout<<"hum(2)"<<endl;
31 }
32 int main(){
33 char c='A';
34 bar(c);//bar(2)
35 short s;//一般情况下,升级转换的优先级高于降级优先级
36 func(s);//调用func(2)
37 hum(2,3.14);//降级转换优于省略号匹配,调用hum(2)
38 return 0;
39 }
3)函数重载的原理
C++编译器是通过对函数进行换名,将参数表的信息整合到函数名中,实现函数重载与名字冲突的矛盾。
例:
int add(int,int){}
intadd(double,int){}
tarena@tarena-virtual-machine:~$g++ -c 3.c
tarena@tarena-virtual-machine:~$nm 3.o
00000005 T_Z3adddi
00000000 T_Z3addii
笔试题:extern “C”的作用
函数声明前加入extern “C” 要求C++编译器不对函数做换名,便于C程序调用该函数
注:extern ”C”修饰的函数无法重载
extern “C” voidfunc(){ …. }
extern “C” {
void func1(){….}
void func2(){….}
}
2、 函数的缺省参数
1) 可以为函数的部分形参或全部形参指定缺省值,调用该函数时,如果不给实参,就取去缺省值作为相应的形参的值
void func(inta,int b=10 ){
cout<<a+b<<endl;
}
int main(void){
func(10) ; // 20
func(10,20); //30
}
2)缺省参数必须靠右侧,如果一个参数有缺省值,那么这个参数右侧所有的参数都必须带有缺省值
void func(inta=10,in b){ //error
cout<<a+b<<endl ;
}
例:
1 #include<iostream>
2 using namespace std;
3 void foo(int a,int b=200,int c=100){
4 cout<<"a="<<a<<endl;
5 cout<<"b="<<b<<endl;
6 cout<<"c="<<c<<endl;
7 }
8 void foo(int i){}
9 int main(void){
10 foo(10,20,30);// 10,20,30
11 foo(10,20);//10,20,100
12 // foo(10); 注意歧义有错误
13 return 0;
14 }
3)如果函数的定义和声明分开,缺省函数应该写在函数声明部分,而定义部分不写但可以加注释。
Void func(int a,int b/*=100*/){ … } ; 函数定义
Void func(int a,int b=100) ; 函数声明
例:
1#include<iostream>
2using namespace std;
3void foo(int a,int b=200,int c=100);//函数声明
4void foo(int i){}
5int main(void){
6 foo(10,20,30);// 10,20,30
7 foo(10,20);//10,20,100
8 // foo(10); 注意歧义有错误
9 return 0;
10 }
11void foo(int a,int b/*=200*/,int c/*=100*/){// 函数定义
12 cout<<"a="<<a<<endl;
13 cout<<"b="<<b<<endl;
14 cout<<"c="<<c<<endl;
15 }
3、 函数的哑元参数
1) 定义:只有类型没有变量名的形参称为哑元。 (实参传过来不用)
void func( int){
…….
}
int main(){
func(10);
}
2)作用:为了兼容以前的代码
算法库:void math_func( int a,int b) {…..}
使用者:
int main(void){
math_func(10,20);
…..
math_func(102,202);
}
==è升级算法库:void math_func(int a,int /*哑元*/) { …..}
int main(void){
math_func(10,20);
…..
math_func(102,202);
}
2) 运算符重载,区分前后++/--
例:
1 #include<iostream>
2 using namespace std;
3 void foo(int /*哑元*/){
4 cout<<"foo(int)"<<endl;
5 }
6 int main(void){
7 foo(100);
8 return 0;
9 }
4、 内联函数inline
笔试题:inline关键字的作用
使用inline 修饰的函数,表示这个函数是一个内联函数,编译器将尝试做内联优化,避免函数调用的开销
(类似宏定义,只是宏定义在预处理执行,内联在编译执行。用空间换时间)
1) 多次调用小而简单的函数适合内联、
2) 调用次数极少或者大而复杂的函数不适合内联
3) 递归函数不适合内联
4) 内联只是一种建议,而不是一个强制的要求,能否做内联优化主要取决于编译器,有些函数不加inline关键字也会做内联优化,有些函数加了inline关键字也不用。
//笔试题
for(inti=0;i<10000000;i++){
for(int j=0;j<1000;j++){
//……
}
}
for(inti=0;i<1000;i++){
for(int j=0;j<10000000;j++){
//……
}
}
下面语句好,减少跳入跳出,连贯性好,提高程序执行效率
二、 C++内存分配
C语言中:malloc( )/free( )
C++中,new /delete 运算符
new运算符用于动态内存分配,delete运算符用于动态内存释放
C:
例:在堆区动态分配内存
int *p=(int*)malloc(sizeof(int));
*p=100;
free(p); 如果不free释放,则内存泄露,浪费内存
p=NULL;
C++:
// int *p=newint;
// *p=100;
等价于 int *p=new int(100);
delete p;
p=NULL;
int *parr=newint [10]
parr[0]=10;
parr[1]=20;
*(parr+2)=30;
……
delete[ ] parr ;
parr = NULL;
例:new指针
1 #include<iostream>
2 using namespace std;
3 int main(void){
4 int *p1=new int;//分配4个字节的内存
5 *p1=100;
6 cout<<*p1<<endl;//100
7 delete p1;// 如果不释放就再使用就会内存泄露
8 p1=NULL;
9
10 p1=new int (200);//分配内存同时初始化
11 cout<<*p1<<endl;//200
12 /*
13 *p1++; 先++再取*;
14 cout<<*p1<<endl; 段错误
15 */
16 (*p1)++;
17 cout<<*p1<<endl; //201
18 delete p1;
19 p1=NULL;
20 return 0;
21 }
new数组空间
1#include<iostream>
2 using namespace std;
3 int main(void){
4 //分配一段连续的内存,sizeof(int)*10
5 int *pa=new int[10];
6 //new数组初始化,C++11标准中支持
7 //int *pa=new int[10]{1,2,3,4,5,6,7,8,9,10};
8 for(int i=0;i<10;i++){
9 pa[i]=i+1;
10 cout<<pa[i]<<' ';
11 }
12 cout<<endl;
13 delete[] pa;//new[] 成对使用
14 return 0;
15 }
三、 C++的引用(reference)
1、定义引用就是给某个变量起别名,对引用的操作和对该变量的操作完全相同
int a=10;在栈区分配4个字节,
int& b=a; // b就是a的别名
b++;
cout<<a<<endl; // 11
2、常引用
1)定义引用时加const修饰,即为常引用,不能通过常引用修改引用的目标
例:
int a=100;
const int&b=a;//b是a常引用
a=200;//OK
b=200;//ERROR
int &r=100; r=200;错误 相当于100=200.
const int&r=100 ; 可以, 常量不做修改
2)普通的引用只能引用左值,常引用也叫做万能引用,既能够引用左值,也能够引用右值。
1 #include<iostream>
2 using namespace std;
3 int main(void){
4 // int& r=100; error
5 const int& r=100;//ok 常量不做修改
6 return 0;
7 }
3)关于左值和右值
左值:可以放在赋值运算符左侧,可以被修改,可以被取地址
int i;
i=100;
++i;
int *p=&i;
注:普通的变量都是左值,前缀表达式和赋值表达式也是左值
(++i)=200; //OK
Cout<<i<<endl;// 200
(i=300)=400;//OK
cout<<i<<endl;// 400
右值:只能放在赋值运算符右侧,不可被修改,不可被取地址
常见的右值:
注:1.字面值常量:10=i ;++10; int *p =&10; 都是错误的
2.大部分的表达式值都是右值:
int a=10; int b=20; (a+b)=30; //error 相当于30=30
3.函数的返回值
int foo(void){
int a=100;
return a;//编译会定义一个临时变量”temp”保存a
}
int main(void){
int res=foo();//函数调用结果就是”temp”
foo()=200;//error
++foo();//error
int *p=&foo();//error
}
例:
1 #include<iostream>
2 using namespace std;
3 int foo(void){
4 int a=100;
5 cout<<"&a="<<&a<<endl;
6 return a;
7 }
8 int main(void){
9 //int& r=foo();error
10 //通过常引用引用函数返回的临时变量
11 const int& r=foo();
12 cout<<"&r"<<&r<<endl;//临时变量的地址
13 int a=10;
14 int b=20;
15 //int& rc=a+b;error
16 const int& rc=a+b;
17 cout<<rc<<endl;//30
18 char ch='A';
19 //int& rch=ch;error
20 const int& rch=ch;
21 cout<<rch<<endl;
22 return 0;
23 }
tarena@tarena-virtual-machine:~$./a.out
&a=0xbfaa445c
&r0xbfaa448c
30
65
3、引用型函数的参数
1)将引用用于函数的参数,可以修改实参变量的值,可以减小函数调用的开销,避免实参到形参值的赋值。(形参直接引用实参,避免了开辟新的内存空间)
1#include<iostream>
2 using namespace std;
3 void swap1(int x,int y){
4 x=x^y;
5 y=x^y;
6 x=x^y;
7 }
8 void swap2(int *x,int *y){
9 *x=*x^*y;
10 *y=*x^*y;
11 *x=*x^*y;
12 }
13 void swap3(int& x,int& y){//避免实虚结合,提高效率
14 x=x^y;
15 y=x^y;
16 x=x^y;
17 }
18 void swap4(const char*& x,constchar*& y){//别名写在变量的前面,类型的后面
19 const char *z=x;
20 x=y;
21 y=z;
22 }
23 int main(void){
24 int a=3;
25 int b=5;
26 swap1(a,b);
27 cout<<"a="<<a<<endl;//3
28 cout<<"b="<<b<<endl;//5
29 swap2(&a,&b);
30 cout<<"a="<<a<<endl;//5
31 cout<<"b="<<b<<endl;//3
32 swap3(a,b);
33 cout<<"a="<<a<<endl;//3
34 cout<<"b="<<b<<endl;//5
35 const char* s1="hello";
36 const char* s2="world";
37 //实现swap4
38 swap4(s1,s2);
39 cout<<s1<<endl;//world
40 cout<<s2<<endl;//hello
41 return 0;
42 }
2)引用型参数有可能意外修改实参变量的值,如果不希望修改实参本身,可以将形参定义为常引用,提高传参效率的同时,可以接受常量型的实参。
1 #include<iostream>
2 using namespace std;
3 struct student{
4 char name[100];
5 int age;
6 };
7 //使用常引用:
8 //1:提高传参效率
9 //2:避免意外修改实参变量本身
10 //3:可接受常量型的实参
11 void print(const student& s){
12 cout<<s.name<<','<<s.age<<endl;
13 }
14 int main(void){
15 const student s={"tang",30};
16 print(s);
17 return 0;
18 }
练习:总结引用的使用、引用和指针的区别
- Day37、函数重载、缺省参数、哑元参数、内联函数inline、内存分配、引用
- day02 C++的函数重载、内联函数 、哑元参数、动态内存分配 、引用
- C++【函数(重载/缺省参数/哑元/内联)】
- C++:布尔类型bool,函数重载、参数缺省值、哑元参数、内联函数、引用
- 一、C++ 内联函数、重载函数、函数的缺省参数
- VS2010 C++ 学习笔记(一) 引用 函数参数默认值 函数重载 内联inline
- Unit02: 重载与缺省参数 、 内联与动态内存分配 、 引用 、 显式类型转换 、 类和对象
- 内联,重载,缺省参数
- 037day(动态内存分配和内联函数,重载函数,函数参数缺省值的学习)
- 函数重载与缺省参数
- 函数重载和缺省参数
- 缺省参数、哑元和内联
- 北大 C++ 1.7 内联函数、函数重载和函数缺省参数
- 【从C到C++学习笔记】内联成员函数/成员函数重载及缺省参数
- c++函数功能 引用 & 重载 & 默认参数 & 内联
- C++学习笔记(四)--内联函数,引用参数,默认参数,函数重载,函数模板
- C++缺省参数和函数重载
- C++初识之函数重载、缺省参数
- javaweb三大框架知识点总结
- Android framwork service添加(manager 远程调service,service jni调native code)
- 在html文档中添加 iconfont 图标
- 原生的搜索分页
- Win10用不了virtualbox
- Day37、函数重载、缺省参数、哑元参数、内联函数inline、内存分配、引用
- 密码学:生日攻击
- Selector
- C++中实现字符串分割方法
- ShareData
- 正则表达式
- Yii 异常处理、事务回滚
- Linux操作系统:文件系统
- windows生成dump文件