函数
【1】函数是什么?
本质:函数是工具
作用:一个函数为了实现一种功能
发展历程:一个函数是为了实现一种客观的需求功能而设计的一种对应工具
通俗一点说,函数其实就是一种工具。程序其实也很简单的,别被哪些老师【专门忽悠学生的人】把你吓着了。
函数是一个功能体。那么,既然是一个功能体,就从现实中的某个例子开始分析一下:什么是函数?即就是,什么是功能体?
比如:一台豆浆机,插上电它就可以运作,那么电资源就是它的运作条件,如同函数必须要放在main()函数内部调用是一样一样的!
如果不插电,也就是说单个功能分析,可以想象一下,豆浆机它要制造豆浆,制造豆浆肯定要有原材料,对不?那什么是它的原材料呢?
好,你可能很清楚,需要豆子。是的,豆子是一类粮食,对吗?OK? Do you understand? 函数的参数,实质上就是这个功能体所需的资源。
只不过模拟现实,各自有了虚拟意义上赋予的类型,现实中人们不在意这样的概念而已。
好,再接着分析,豆浆机把豆子放进去,然后插上电,再打开电源,开始磨豆浆。
过几分钟【其实这就是进程的经典概念】后,关掉电源,打开豆浆机,倒出来的就是你梦寐以求的豆浆。
这样子就好理解了,哦!那也就是说,函数的返回值就是所谓的这个功能体的功能实现的结果!
OK!这样子我们就很简单的把函数这个编程的基本概念元素完全给征服了!
好吧,那么既然这样子的话,我们下面再继续理解专业领域的函数:
1 int add(int a, int b) 2 { 3 return a + b; 4 }
这是一个函数,那么,它就是一个功能体,好,它实现怎样的功能呢?对了,一目了然,只有一行代码,实现两个int类型的数据相加的运算,返回值类型仍然是int。
这就达到了绝对的统一。
函数这个东西很神奇的。怎么说呢?
就像人一样的。人也是一个功能体,你吃进去什么类型的都有,然而最后排出来的却是一种类型的(呵呵,这个例子不雅观,但是很说明问题!)。
函数也是这样子的。参数可以有很多种类型,但是最后的结果只有一种类型。
【2】函数有哪几种返回形式?
答案:一般为引用返回,指针返回,值返回。下面就函数返回类型举例如下:
(1)引用返回
<1> 示例1代码如下:
1 #include <iostream> 2 using namespace std; 3 4 int & fun() 5 { 6 static int a = 10; 7 return a; 8 } 9 10 int main() 11 { 12 int x = fun(); // 以int类型接受 13 cout << "x = " << x << endl; // x = 10 14 int &y = fun(); // 以引用类型接受 15 cout << "y = " << y << endl; // y = 10 16 fun() = 100; // 引用返回时,这里是可以修改函数值的 17 int &s = fun(); 18 cout << "s = " << s << endl; // s = 100 19 int b = 0; 20 b = fun(); 21 cout << "b = " << b << endl; // b = 100 22 b = ++fun(); // 引用返回时,这里是可以修改的 23 cout << "b = " << b << endl; // b = 101 24 b = 120; // 引用返回时,这里也是可以修改的 25 cout << "b = " << b << endl; // b = 120 26 27 system("pause"); 28 return 0; 29 } 30 31 /* out: 32 x = 10 33 y = 10 34 s = 100 35 b = 100 36 b = 101 37 b = 120 38 */
<2> 示例2代码如下:
1 #include <iostream> 2 using namespace std; 3 4 class Test 5 { 6 public: 7 Test(int x = 0) : value(x) 8 { 9 cout << "Create Test : " << endl; 10 } 11 ~Test() 12 { 13 cout << "Destroy Test : " << endl; 14 } 15 16 public: 17 int & GetRef() 18 {// Test * const this 19 cout << ":: GetRef" << endl; 20 return value; 21 } 22 const int & GetRef() const 23 {// const Test * const this; 24 cout << ":: const GetRef" << endl; 25 return value; 26 } 27 28 private: 29 int value; 30 }; 31 32 int main() 33 { 34 Test t1(10); 35 const Test t2(20); 36 37 int a1 = t1.GetRef(); 38 int &b1 = t1.GetRef(); 39 const int &c1 = t1.GetRef(); 40 41 int a2 = t2.GetRef(); 42 // int &b2 = t2.GetRef(); // error!!!cannot convert from 'const int' to 'int &' 43 const int &c2 = t2.GetRef(); 44 45 return 0; 46 } 47 48 /* 49 Create Test : 50 Create Test : 51 :: GetRef 52 :: GetRef 53 :: GetRef 54 :: const GetRef 55 :: const GetRef 56 Destroy Test : 57 Destroy Test : 58 */
(2)指针返回
<1> 示例1代码如下:
1 #include <iostream> 2 using namespace std; 3 4 int* fun() 5 { 6 static int *p = new int(10); 7 cout << "p :: " << p << endl; 8 return p; 9 } 10 11 int main() 12 { 13 int *s = NULL; 14 s = fun(); // 意味着是S,P指向了同一个内存 15 cout << "s :: " << s << endl; 16 cout << "*s :: " << *s << endl; 17 s = new int(100); // s指针另外指向了一个内存 18 // fun() = new int(100); // 这种情况是不可以直接赋值的 19 20 return 0; 21 } 22 23 /* 24 p :: 0323A3F8 25 s :: 0323A3F8 26 *s :: 10 27 */
<2> 示例2代码如下:
1 #include <iostream> 2 using namespace std; 3 4 class Test 5 { 6 public: 7 Test(int x = 0) : value(x) 8 { 9 cout << "Create Test : " << endl; 10 } 11 ~Test() 12 { 13 cout << "Destroy Test : " << endl; 14 } 15 16 public: 17 int *GetPtr() 18 { 19 cout << ":: GetRef" << endl; 20 return &value; 21 } 22 const int * GetPtr() const 23 { 24 cout << ":: const GetRef" << endl; 25 return &value; 26 } 27 28 private: 29 int value; 30 }; 31 32 int main() 33 { 34 Test t1(10); 35 const Test t2(20); 36 37 int *a1 = t1.GetPtr(); 38 int * const &b1 = t1.GetPtr(); 39 const int * const &c1 = t1.GetPtr(); 40 41 const int *a2 = t2.GetPtr(); 42 const int * const &b2 = t2.GetPtr(); 43 const int * const &c2 = t2.GetPtr(); 44 45 return 0; 46 } 47 48 /* 49 Create Test : 50 Create Test : 51 :: GetRef 52 :: GetRef 53 :: GetRef 54 :: const GetRef 55 :: const GetRef 56 :: const GetRef 57 Destroy Test : 58 Destroy Test : 59 */
(3)值返回
示例代码如下:
1 #include <iostream> 2 using namespace std; 3 4 class Test 5 { 6 public: 7 Test(int x = 0) : value(x) 8 { 9 cout << "Create Test : " << endl; 10 } 11 ~Test() 12 { 13 cout << "Destroy Test : " << endl; 14 } 15 16 public: 17 int GetValue() 18 {// Test * const this; 19 cout << ":: GetValue" << endl; 20 return value; 21 } 22 int GetValue() const 23 {// const Test * const this; 24 cout << ":: const GetValue" << endl; 25 return value; 26 } 27 28 private: 29 int value; 30 }; 31 32 int main() 33 { 34 Test t1(10); 35 const Test t2(20); // 常对象(意味着只可以调用常方法) 36 37 int a1 = t1.GetValue(); 38 cout << a1 << endl; 39 // int &b1 = t1.GetValue(); // error!!!引用必须是一个具体的已存在的同类对象 40 // 等价于 41 // int &b1 = 10; // error!!! cannot convert from 'int' to 'int &' 42 const int &c1 = t1.GetValue(); 43 // 等价于 44 // const int &c1 = 10; 45 cout << c1 << endl; 46 47 int a2 = t2.GetValue(); 48 cout << a2 << endl; 49 // int &b2 = t2.GetValue(); // error!!! 原因同上 50 const int &c2 = t2.GetValue(); 51 cout << c2 << endl; 52 53 return 0; 54 } 55 56 /* 57 Create Test : 58 Create Test : 59 :: GetValue 60 10 61 :: GetValue 62 10 63 :: const GetValue 64 20 65 :: const GetValue 66 20 67 Destroy Test : 68 Destroy Test : 69 */
(4)指针引用返回
示例代码如下:
1 #include <iostream> 2 using namespace std; 3 4 int * const & fun() 5 { 6 static int *p = new int(10); // 静态指针 7 return p; 8 } 9 10 int main() 11 { 12 int *s = NULL; 13 s = fun(); // 返回值必须赋予指针类型变量 14 s = new int(10); 15 int * const &r = fun(); // 如果是指针引用,必须为常引用 16 // r = new int(10); // 此时,因为是常引用所以不可修改 17 // fun() = new int(100); // 因为是常引用指针类型所以不可直接修改 18 19 return 0; 20 }
【3】函数类型如何分析?
让我们来看下面一段代码:
1 #include <iostream> 2 using namespace std; 3 4 typedef int Func(int, int); // 定义函数类型; 类型名为Func 5 6 int add(int a, int b) 7 { 8 return (a + b); 9 } 10 11 int max(int a, int b) 12 { 13 return (a > b ? a : b); 14 } 15 16 void press(int x, int y, Func c) // 注意:c为一个函数变量 17 { 18 int z = c(x, y); 19 cout << z << endl; 20 } 21 22 int main() 23 { 24 press(12, 23, add); // 实参为函数名add 25 press(23, 34, max); // 实参为函数名max 26 27 return 0; 28 } 29 30 /* 31 35 32 34 33 */
如上,关于typedef不懂的可以参考随笔《typedef关键字》
【4】函数指针与函数类型如何区别?
示例代码如下:
1 #include <iostream> 2 using namespace std; 3 4 int max(int a, int b) 5 { 6 return (a > b ? a : b); 7 } 8 int add(int a, int b) 9 { 10 return (a + b); 11 } 12 13 typedef int(*pFun)(int, int); // 函数指针类型定义 14 typedef int PFUN(int, int); // 函数类型定义 15 16 void press(pFun a, PFUN b) // Question1 : ?为什么作为函数参数声明时成立? 17 { 18 cout << a(12, 23) << endl; 19 cout << b(12, 23) << endl; 20 } 21 22 int main() 23 { 24 pFun a = add; 25 // PFUN c = add; // syntax error!!! Question2 : ?为什么在定义时不可以? 26 // void va; // 注意:PFUN 与 void一样是一种类型名,但是不可以定义变量 27 PFUN *b = add; // PFUN * 即表示函数指针类型 28 press(add, max); 29 30 return 0; 31 }
注意:Question1 和 Question2,即自定义的函数类型名作为函数的形参类型是可以的,但是作为变量的类型是不允许的。为什么呢?
有一个词,一直以来,尤其特别相当推崇,即自洽,能自圆其说的意思。
仔细观察上例第24行:函数名直接赋值于函数指针。
再看、再看、再看第25行:函数名直接赋值于函数类型。
反证法:如果25行能通过语法预编译,那么pFun类型与PFUN *类型有什么区别呢?该如何区分呢?
这样子想一想,Question1 与 Quention2 的疑惑应该迎刃而解了。
【5】关于函数指针数组注意事项?
示例代码如下:
1 #include <iostream> 2 using namespace std; 3 4 typedef int(*pFun)(int, int); // 函数指针类型定义;类型名为pFun 5 6 typedef int ARRAY[5]; // 数组类型定义; 类型名为ARRAY 7 8 int max(int a, int b) 9 { 10 return (a > b ? a : b); 11 } 12 13 int add(int a, int b) 14 { 15 return (a + b); 16 } 17 18 int main() 19 { 20 ARRAY a, b; // 定义两个数组a 和 b 21 pFun c; // 定义函数指针c 22 23 int (*d)(int, int); // 声明函数指针d 24 25 pFun pf[2] = {add, max}; // 初始化函数指针数组 26 27 pFun(*p)[2] = &pf; // 初始化函数指针数组指针 28 29 int(*pfun[2])(int, int) = {add, max}; // 定义函数指针数组并初始化 30 int(*(*s)[2])(int, int) = &pfun; // 定义函数指针数组的指针并初始化 31 32 return 0; 33 }
【6】函数参数的调参顺序如何?
请看如下示例代码,用心观察,总结结论。
示例代码如下:
1 include <iostream> 2 using namespace std; 3 4 void Fun(int a, int b = 0, int c = 0, int d = 0) 5 { 6 cout << "a = " << a << endl; 7 cout << "b = " << b << endl; 8 cout << "c = " << c << endl; 9 cout << "d = " << d << endl; 10 } 11 12 int main() 13 { 14 cout << "Fun(12)" << endl; 15 Fun(12); 16 cout << "Fun(12, 23)" << endl; 17 Fun(12, 23); 18 cout << "Fun(12, 23, 34)" << endl; 19 Fun(12, 23, 34); 20 21 return 0; 22 } 23 24 /* 25 Fun(12) 26 a = 12 27 b = 0 28 c = 0 29 d = 0 30 Fun(12, 23) 31 a = 12 32 b = 23 33 c = 0 34 d = 0 35 Fun(12, 23, 34) 36 a = 12 37 b = 23 38 c = 34 39 d = 0 40 */
当函数参数有默认值时,实参与形参的对应关系如上。可以参见随笔《为什么C++函数形参默认值从最末一个赋值?》
【7】如何实现一个不定形参函数?
示例代码如下:
1 #include <iostream> 2 using namespace std; 3 4 #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 5 // 4 + 4 - 1=7 //4-1=3 6 // 0111 //~0011=1100 7 //0111&1100=0100 =4 8 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 9 //指针= (char*)&V(数值个数) + 4 10 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 11 //(*(int *)((指针ap += INTSIZEOF(int))-INTSIZEOF(int))) 12 //*(int *) ((ap=ap+INTSIZEOF(int))-INTSIZEOF(int)) 13 //*(int *)(本段代码执行结果ap向前走4个字节,但是地址不变) 14 #define va_end(ap) ( ap = (va_list)0 ) 15 //ap=(char *)0 16 17 int average(int n_values, ...) 18 { 19 int sum = 0; 20 21 va_list var_arg; //char * 22 23 va_start(var_arg, n_values); 24 25 for (int i = 0; i < n_values; ++i) 26 { 27 sum += va_arg(var_arg, int); 28 } 29 30 va_end(var_arg); 31 return (sum / n_values); 32 } 33 34 int main() 35 { 36 cout << average(4, 10, 20, 30, 40) << endl; //(10 + 20 + 30 + 40) / 4 = 25 37 38 return 0; 39 } 40 41 /* 42 25 43 */
希望有所收获,仅此而已。
Good Good Study,Day Day Up.
顺序 选择 循环 总结