内联函数
在C++中内联函数是为了解决使用宏出现的一些问题,而引入的
宏函数的缺陷:代码中列举了两种情况
#include <iostream>
#include <string>
using namespace std;
//内联函数
//定义一个加法 使用宏的时候需要加上对应的括号,
//要不在预处理阶段会出现,计算优先级的问题
#define MyAdd(x,y) ((x)+(y))
void test01()
{
int ret = MyAdd(10,20)*20; //预期结果600 (10+20)*30 = 410
cout<<"ret = " << ret <<endl;
}
//大小比较
#define MyCompore(a,b) ((a) < (b) ? (a) : (b))
void test02()
{
int a = 10;
int b = 20;
int ret = MyCompore(a,b); //(10) < (20) ? (10) : (20)
cout<<"ret = " << ret <<endl;
int ret1 = MyCompore(++a,b); //(++10) < (20) ? (++10) : (20)
cout<<"ret1 = " << ret1 <<endl; //按照正常逻辑返回的应该是11
}
//宏函数也没有作用域
int main()
{
//test01();
test02();
return 0;
}
为了解决这样的缺陷就引入了内联函数
内联函数的注意事项:
1.内联函数需要加inline关键字
2.类内部的成员函数前面默认会加inline关键字
3.内联函数和编译器
在某些情况下编译器不会把函数转化为内联函数
内联函数不能存在任何形式的的循环语句(开销比较大)
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作(最后函数体会被替换,就没有函数的地址了)
note:这个在撸代码的时候经常可以看见.h文件中,有的函数前面会加上这个关键字
函数的默认参数以及占位
在C语言中没有默认参数和占位参数
1.参数可以有默认值
函数参数u注意事项,如果一个位置有默认参数,如果一个位置有了默认参数,那么从这个位置从左往右都必须有默认参数
2.函数的声明和实现只能有一个有默认值(二义性)
3.函数有占位符(占位符也可以有默认值),调用的时候必须要提供这个参数
#include <iostream>
#include <string>
using namespace std;
//1.函数的默认参数 参数后面 = ...
//函数参数u注意事项,如果一个位置有默认参数,如果一个位置有了默认参数
//那么从这个位置从左往右都必须有默认参数
//传入参数,如果有参数,就用参数的值,没有参数就用默认值
void func(int a ,int b = 10, int c = 20)
{
cout <<"a + b + c= " <<a + b + c<< endl;
}
void test01()
{
func(1,2);
}
//2.如果函数声明里面有了默认参数,那么函数实现必须没有
//函数声明和实现里,只能有一个里面有默认参数,会出现二义性
void func2(int a = 10, int b = 10);
void func2(int a,int b)
{
}
//3.函数的占位
//如果有了占位参数,函数调用的时候必须要提供这个参数,但是用不到
//占位参数,没有很大的用处 ++重载会用到
//占位参数可以有默认值
void func3(int a, int = 1)
{
}
void test02()
{
func3(10,1);
}
int main()
{
//test01();
test02();
return 0;
}
函数重载
1.基本语法:
1)函数名称相同在同一个作用域,
2)函数参数的个数、类型、顺序不同
3)函数的返回值不可以作为函数的重载条件(二义性)
4)当函数重载遇到默认参数,注意避免二义性。
#include <iostream>
#include <string>
using namespace std;
//函数重载的基本语法
//在C++中函数名称可以重复
//必须在同一作用域,函数名称相同
//函数的参数 个数 或 类型 或 顺序 不同
void func()
{
cout<<"this func is not argument"<<endl;
}
void func(int a)
{
cout<<"this func is have argument (int a)"<<endl;
}
void func(double b)
{
cout<<"this func is have argument(double b)"<<endl;
}
void func(int a,double b)
{
cout<<"this func is have argument(int a,double b)"<<endl;
}
void func(double b,int a)
{
cout<<"this func is have argument(double b,int a)"<<endl;
}
//返回值可以作为函数重载的条件吗? 不可以 在调用的是出现了二义性
//int func(double b,int a)
//{
// cout<<"this func is have argument(double b,int a)"<<endl;
//}
//当函数重载碰到了默认参数的时候,要注意避免二义性
//void func2(int a, int b = 10)
//{
//
//}
//
void func2(int a)
{
}
//引用的函数重载
void func3(int &a) //引用必须要引合法的内存空间
{
cout<<"int &a"<<endl;
}
void func3(const int &a) //const也是可以作为重载的条件 int tmp = 10; const int &a = temp;
{
cout<<"const int &a"<<endl;
}
void test01()
{
func();
func(1);
func(1, 1.1);
func(1.1, 1);
}
void test02()
{
func2(10);
}
void test03()
{
int a = 10;
//func3(a);
func3(10); //引用必须要引合法的内存空间
}
int main()
{
//test01();
//test02();
test03();
return 0;
}
2.函数重载的实现
编译器为了实现函数的重载,也是默认为我们做了一些幕后工作,编译器用不同的参数类型来修饰不同的函数名,例如:void func(); 编译器可能会将函数名修饰成_func,当编译器碰到void func(int a);编译器可能会将函数名修饰成_func_int,当编译器碰到void func(int a,char b);编译器可能会将函数名修饰成_func_int_char,编译器不同内部的处理方式也会不同,因为编译器如何修饰重载函数没有同一的标准,所以不同编译器可能会出现不同的内部名。
void func(){}
void func(int x){}
void func(int x,char y){}
以上三个函数在linux下生成的编译之后的函数名为
_Z4funcv() //v 代表void,无参数
_Z4funci() //i 代表int,参数类型为int
_Z4funcic() //i 代表第一个参数类型为int,c代表第二个参数类型为int