1)定义
在相同作用域,可以定义同名的函数,但是参数必须有所区分,这样函数构成重载关系.
注:函数重载和返回类型无关。
eg:实现图形库中一些绘图函数
//C语言
void drawRect(int x,int y,int w,int h){}
void drawCircle(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){}
...
举例:overload1.cpp
#include
using namespace std;
int func(int i){
cout << "func(int)" << endl;
}
void func(int a,int b){
cout << "func(int,int)" << endl;
}
void func(int i,float f){
cout << "func(int,float)" << endl;
}
int main(void){
func(10);//调用func(int i)
func(10,20);//调用func(int a,int b)
//func(10,3.14);//歧义错误,因为3.14是double类型
func(10,3.14f);//func(int,float)
//由函数指针类型决定匹配的重载版本
void (*pfunc)(int,float) = func;
pfunc(10,20);
return 0;
}
2)函数重载匹配
调用重载关系的函数时,编译器将根据实参和形参的匹配程度,自动选择最优的重载版本,当前g++编译器匹配一般规则:
完全匹配>=常量转换>升级转换>降级转换>省略号
举例overload2.cpp
#include
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 hum(char c){
cout << "hum(1)" << endl;
}
//short->int:升级转换
void hum(int i){
cout << "hum(2)" << endl;
}
//省略号匹配
void fun(int i,...){
cout << "fun(1)" << endl;
}
//double->int:降级转换
void fun(int i,int j){
cout << "fun(2)" << endl;
}
int main(void){
char c = 'a';
bar(c);//优先考虑常量转换调用bar(const char c)
short s = 100;
hum(s);//优先考虑升级转换调用hum(int i)
fun(100,3.14);//优先考虑降级转换fun(int i,int j)
return 0;
}
3)函数重载原理
C++的编译器在编译函数时,会进行换名,将参数表的类型信息整合到新的函数名中,因为重载关系的函数参数表有所区分,换出的新的函数名也一定有所区分,解决了函数重载和名字冲突的矛盾。
笔试题:C++中extern "C"作用?
在C++函数声明时加extern "C",要求C++编译器不对该函数进行换名,便于C程序直接调
用该函数.
注:extern "C"的函数无法重载。
1)可以为函数参数指定缺省值,调用该函数时,如果不给实参,就取缺省值作为默认实参。
void func(int i,int j=0/缺省参数/){}
2)靠右原则:如果函数的某个参数带有缺省值,那么该参数右侧的所有参数都必须带有缺省值。
3)如果函数的声明和定义分开写,缺省参数应该写在函数的声明部分,而定义部分不写。
举例:defArg.cpp
#include
using namespace std;
//函数声明
void func(int a,int b = 20,int c = 30);
//void func(int i){}//注意歧义错误
int main(void){
func(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;
}
1)定义函数时,只有类型而没有变量名的形参被称为哑元
void func(int){…}
2)需要使用哑元场景
–》在操作符重载函数中,区分前后++、-- //后面讲
–》兼容旧的代码
算法库:void math_func(int a,int b){...}
使用者:
int main(void){
...
math_func(10,20);
...
math_func(10,20);
...
}
-----------------------------------------
升级算法库:void math_func(int a,int/*哑元*/){...}
使用者:
int main(void){
...
math_func(10,20);
...
math_func(10,20);
...
}
1)使用inilne关键字修饰的函数,即为内联函数,编译器将会尝试进行内联优化,可以避免函数调用开销,提高代码执行效率.
inline void func(void){…}
2)使用说明
–》多次调用小而简单的函数适合内联优化
–》调用次数极少或大而复杂的函数不适合内联
–》递归函数不能内联优化
–》虚函数不能内联优化//后面讲
注:内联只是一种建议而不是强制的语法要求,一个函数能否内联优化主要取决于编译器,有些函数不加inline修饰也会默认处理为内联优化,有些函数即便加了inline修饰也会被编译器忽略。
1)分配:malloc()
2)释放:free()
1)分配:new/new[]
2)释放:delete/delete[]
举例:new.cpp
#include
using namespace std;
int main(void){
//动态分配内存保存1个int数据
//int* pi = (int*)malloc(4);//C
int* pi = new int;//C++
*pi = 123;
cout << *pi << endl;
//free(pi);
delete pi;//防止内存泄露
pi = NULL;//避免野指针
//动态分配内存同时初始化
int* pi2 = new int(200);
cout << *pi2 << endl;//200
(*pi2)++;
cout << *pi2 << endl;//201
delete pi2;
pi2 = NULL;
//动态分配内存保存10个int
//int* parr = new int[10];
//new数组同时初始化,需要C++11支持
int* parr =
new int[10]{1,2,3,4,5,6,7,8,9,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;
return 0;
}
举例:delete.cpp
#include
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;
}
1)引用即别名,引用就是某个变量别名,对引用操作和对变量本身完全相同.
2)语法
类型 & 引用名 = 变量名;
注:引用必须在定义同时初始化,而且在初始化以后所绑定的目标变量不能再做修改.
注:引用类型和绑定目标变量类型要一致。
eg:
int a = 10;
int & b = a;//b就是a的别名
b++;
cout << a << endl;//11
a++;
cout << b << endl;//12
int c = 123;
b = c;//仅是赋值
cout << a << endl;//123
举例:reference.cpp
#include
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++;
cout << "a=" << a << ",b=" << b << endl;
//int& r;//error,引用定义时必须初始化
int c = 20;
b = c;//ok,但不是修改引用目标,仅是赋值
cout << "a=" << a << ",b=" << b << endl;
cout << "&a=" << &a << ",&b=" << &b<<endl;
//char& rc = c;//error,引用类型和目标要一致
return 0;
}
1)定义引用时可以加const修饰,即为常引用,不能通过常引用修改目标变量.
const 类型 & 引用名 = 变量名;
类型 const & 引用名 = 变量名;//和上面等价
int a = 10;
const int& b = a;//b就是a常引用
cout << b << endl;//10
b++;//error
举例:constRef.cpp
#include
using namespace std;
int main(void){
//int& r1 = 100;//error
const int& r1 = 100;//ok
cout << r1 << endl;//100
int a=10,b=20;
//int& r2 = a+b;//error
//r2引用的是a+b表达式结果的临时变量(右值)
const int& r2 = a+b;
cout << r2 << endl;//30
return 0;
}
2)普通引用也可以称为左值引用,只能引用左值;而常引用也可以称为万能引用,既可以引用左值也可以引用右值。
3)关于左值和右值
左值(lvalue):可以放在赋值表达式左侧,可以被修改
右值(rvalue):只能放在赋值表达式右侧,不能被修改
练习:测试下面表达式结果,是左值还是右值?
int a,b;
a+b;//右值
a+=b;
++a;
a++;
练习:总结关于引用和指针区别和联系(手机百度)