五、函数
一、内联函数
1.1 内联函数的引出
1.1.1 宏函数的缺陷
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; #define MyAdd(x, y) x+y #define MyCompare(a,b) (a)<(b)?(a):(b) void test01() { int ret = MyAdd(10, 20); cout << "ret = " << ret << endl; // ret = 30 ret = MyAdd(10, 20) * 20; // 预期结果是 600 // 实际上结果是 410 = 10 + 20 * 20 = 410, 所以宏定义的时候应该加上括号 #define MyAdd(x, y) (x+y) cout << "ret = " << ret << endl; // ret = 410 } void test02() { int a = 10; int b = 20; int ret = MyCompare(a, b); cout << "ret = " << ret << endl; // ret = 10 ret = MyCompare(++a, b); // 预期结果是 11 // 实际上结果是 12 (++a)<(b)?(++a):(b) // 刚开始 ++a之后, a=11, 返回的时候又一次++a, a=12 cout << "ret = " << ret << endl; // ret = 12 } int main() { test01(); test02(); return EXIT_SUCCESS; }
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; void mycompare(int a, int b) { int ret = a < b ? a : b; cout << "ret = " << ret << endl; } void test03() { int a = 10; int b = 20; mycompare(++a, b); // ret = 11 } int main() { test03(); return 0; }
// 在普通函数(非成员函数)前面加上 inline关键字就成为了内联函数 // inline void fun(int a) // 这样的写法没有任何效果,只是声明函数 inline void fun(int a) { return a++; // 内联函数必须要和函数体结合在一起才会起作用 } /* 注意:编译器将会检查函数参数列表使用是否正确, 并返回值(进行必要的转换)。之这些事是预处理器无法完成的。 内联函数的确占用空间,但是内联函数相对于普通函数的优势只是省却了函数调用时候的压栈,跳转,返回的开销,我们可以理解为内联函数是以空间换时间。 */ 、 // 注意: 内联函数的声明 inline void fun(); void fun() { }; // 如果函数实现的时候,没有加上 inline, 那么这个函数依然不算内联函数
C++ 内联函数也会有一些限制,以下情况比那一起可能不会将函数进行内联编译
1. 不能存在任何形式的循环语句
2. 不能存在过多条件判断语句
3. 函数体不能过于庞大
4. 不能对函数进行取值操作
内联只是编译器一个建议,编译器不一定会接受这种建议。如果没有将函数声明位内联函数,那么编译器也可能将函数作为内联函数,一个好的编译器会自动内联小的,简单的函数、
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; // 函数的默认参数, 在参数后面 = ... // 函数参数的注意事项:如果有一个位置有了默认参数,那么从这个位置开始,后面的都必须要有默认参数 // 传入参数,如果有参数,就用传入的参数,没有参数就用默认值 void fun01(int a = 10, int b = 10) { cout << "a + b = " << a + b << endl; } void fun02(int a, int b = 10, int c = 20) { cout << "a + b + c = " << a + b + c<< endl; } void test01() { fun01(); // a + b = 20 fun02(1); // a + b + c = 31 fun02(1, 2); // a + b + c = 23 } int main() { test01(); return EXIT_SUCCESS; }// 如果函数声明里面有了默认参数, 函数实现时候必须没有默认参数。 也就是函数声明和实现里只能有一个默认参数,不要同时出现默认参数。 // 如: void Func(int a = 10; int b = 20); // 声明 void Func(int a = 10; int b = 20) // 实现的时候编译就会报错 { }
// C语言中没有占位参数 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; // int 后面没有形参就是展位参数。函数调用的时候必须要提供这个参数,但是用不到 // 占位参数没有什么大用途, 只要重载 ++ 符号才有点用 // 占位参数可以有默认值, 如 int = 1 void func(int a, int) { ; } int main() { func(10, 1); return EXIT_SUCCESS; }
四、函数重载
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; // 函数重载 // C++中函数名称可以重复 // 必须在同一个作用域下, 函数名称相同 // 函数的参数个数不同,或者类型不同,或者顺序不同 // 函数返回值不同不能作为函数重载的条件 void fun() { cout << "无参数的func" << endl; } void fun(int a) { cout << "有参数的func(int a)" << endl; } void fun(double a) { cout << "有参数的func(double a)" << endl; } void fun(double a, int b) { cout << "有参数的func(double a, int b)" << endl; } void fun(int a, double b) { cout << "有参数的func(int a, double b)" << endl; } void test01() { fun(); fun(1); fun(1.1); fun(1.1, 3); fun(3, 1.1); } int main() { test01(); return EXIT_SUCCESS; }
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; // 函数重载碰到了默认参数的时候,要注意避免二义性的问题 void func02(int a, int b = 10) { } void func02(int a) { } void test() { // func02(10); // 报错,不知道调用哪一个 } int main() { test(); return EXIT_SUCCESS; }
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; void func03(int &a) { cout << "int &a" << endl; } void func03(const int &a) // const 也是可以作为重载的条件 { cout << "const int &a" << endl; } void test03() { int a = 10; func03(a); // int &a func03(10); // const int &a } int main() { test03(); return EXIT_SUCCESS; }
// 在linux中 void func() {}; void func(int x) {}; void func(int x, char y) {}; // 在linux中编译过后的函数名为 _Z4funcv // v代表void _Z4funci // i代表int _Z4funcic // i代表第一个参数int,c代表第二个参数char
五、extern "C" 浅析
// test.h #pragma once #include<stdio.h> void show(); // test.c #include "test.h" void show() { printf("Hello World\n"); }// main.c #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> //#include "test.h" using namespace std; // C++中想调用C语言方法 extern "C" void show();// 代表show方法按照 C语言来处理。使用了 外部的 show,但是 #include "test.h" 又包含了 show',所以 #include "test.h" 就可以不需要了 // 如果 需要的C的函数太多了,如果每一个函数都这样 extern "C" 这样就太复杂了, 所以我们都是在 .h 中直接修改,具体修改方式见 5.2 节 int main() { show(); // 直接调用show()的时候,报错, 无法解析的外部符号 // 在 C++中,函数是可以发生重载的,编译器会把这个函数名偷偷改变, 如可能改称为 _showv了,所以调用show的时候报错 return EXIT_SUCCESS; }
// test.h #pragma once #ifdef __cplusplus // 两个 _ extern "C" { #endif // !__cplusplus #include<stdio.h> void show(); // 其他的C语言函数 #ifdef __cplusplus // 两个 _ } #endif // !__cplusplus// main.c 修改为 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include "test.h" // 此时需要这个了 using namespace std; int main() { show(); // 直接调用show()的时候,报错, 无法解析的外部符号 // 在 C++中,函数是可以发生重载的,编译器会把这个函数名偷偷改变, 如可能改称为 _showv了,所以调用show的时候报错 return EXIT_SUCCESS; }