代码改变世界

学习C++ -> 进一步了解函数

2013-01-25 21:42  wid  阅读(10315)  评论(5编辑  收藏  举报

学习C++ -> 进一步了解函数




一、函数的参数传递
    1>. 值传递
        值传递是指向函数传递自身的一个副本, 也可以认为是自身的克隆, 他最大的一个特点就是函数对传入的副本进行操作不会影响到实参的本身, 看一个示例, 我们想通过函数来改变一个变量的值:

 1         #include<iostream>
 2 
 3         using namespace std ;
 4 
 5         void fun(int val)
 6         {
 7             val = 100 ;     //将传进来的参数的值更改为100
 8         }
 9 
10         int main()
11         {
12             int n = 0 ;
13             fun(n) ;        //尝试通过函数改变n的值
14             cout<<"n = "<<n ;
15 
16             return 0 ;
17         }

 
    输出:

    n = 0
    Process returned 0 (0x0)   execution time : 0.031 s
    Press any key to continue.


        通过输出的结果可以看到, n的值并未发生任何改变。
        


    2>. 指针传递
        一个有效的指针变量中存放的是该变量的地址, 向函数参数中传递指针就意味着函数能根据指针指向的地址来找到这个变量的实际存储位置, 对实际位置中的内容进行操作, 实参的值自然就会跟着改变, 看一个示例:

 1         #include<iostream>
 2 
 3         using namespace std;
 4 
 5         void fun(int *p)
 6         {
 7             *p = 100 ;      //通过指针p改变实参的值
 8         }
 9 
10         int main()
11         {
12             int n = 0 ;
13             int *p = &n ;
14             fun(p) ;        //将指向变量n的指针传入到函数fun
15             cout<<"n = "<<n ;
16 
17             return 0 ;
18         }


        输出:

        n = 100
        Process returned 0 (0x0)   execution time : 0.625 s
        Press any key to continue.


        很明显, 将指针作为参数传递到函数后, 函数对该指针进行操作就直接影响到了实参n的值。
        


    3>. 引用传递
        引用传递函数也具有"异地"操作实参的能力, 与指针相比倒是省去了定义指针变量所开辟的空间, 并且在使用时的风险比指针要低, 引用不是实参的"副本", 而是真实的指向实参值在内存中的地址, 所以对引用进行操作同样也等同于对实测进行操作。

 1         #include<iostream>
 2 
 3         using namespace std;
 4 
 5         void fun(int &r)
 6         {
 7             r = 100 ;      //通过引用改变实参的值
 8         }
 9 
10         int main()
11         {
12             int n = 0 ;
13             int &rn = n ;
14             fun(rn) ;        //传递n的引用rn
15             cout<<"n = "<<n ;
16 
17             return 0 ;
18         }

 

 




二、函数的默认参数
    所谓的默认参数是指在调用时可以省略该参数, 即不传入参数, 一个示例:

 1     #include<iostream>
 2 
 3     using namespace std;
 4 
 5     void fun(int n = 100)        //声明参数列表时将形参n的值赋值为100, 表示默认值
 6     {
 7         cout<<"n = "<<n<<endl ;
 8     }
 9 
10     int main()
11     {
12         cout<<"使用默认参数:" ;
13         fun() ;     //使用默认参数形式调用函数
14 
15         cout<<"使用自定义参数:" ;
16         fun(200) ;  //向参数内传递值200
17 
18         return 0 ;
19     }

 
    输出:

    使用默认参数:n = 100
    使用自定义参数:n = 200

    Process returned 0 (0x0)   execution time : 0.766 s
    Press any key to continue.

 
    默认参数的一大特点就是当不传入参数时函数自动调用默认的参数值, 而当我们传入参数时, 函数便不再理会默认的参数值, 转而使用传递进来的参数值。
    
    使用函数默认参数需要注意的问题:
        参数默认必须是按从后向前的顺序, 例如 fun(int b, int n = 100) 这样是合法的, 而 fun(int n = 100, int b) 就是不合法的, 因为编译器会将传入的参数一一对应, 传入1个参数时编译器就会与默认参数对应起来, 此时b就没有传入参数, 也就自然报错了。如果传入两个那么默认参数也就没有存在的意义, 所以编译器规定参数默认必须是按从后向前。
        
        

 

 


三、inline函数
    inline 函数又称 "内联函数", 他主要运用在函数体重执行的语句较少但又会被频繁调用的函数中, 例如调用函数输出10000条"hello":

 1     #include<iostream>
 2     using namespace std;
 3 
 4     void fun()
 5     {
 6         cout<<"Hello, world!\n" ;
 7     }
 8 
 9     int main()
10     {
11         int i ;
12         for(i=0; i<10000; i++)
13             fun() ;             //短时间内将会被调用10000次
14 
15         return 0 ;
16     }

 
    fun函数只有一个功能, 就是输出一条 "Hello, world!", 所以在main函数内我们通过控制for循环的方式调用10000次fun函数来实现这个功能, 那么这么做有什么不妥呢?
    
    先来从大致上了解下函数的调用过程:
        在一个函数中调用另一个函数, 系统首先会中断原函数的执行, 在中断时需要做一些现场保护工作, 记录当前函数的中断时的一些信息以便被调函数执行完后原函数的继续执行, 记录完成后才会把执行的流程转向被调函数, 等被调函数执行完后再返回原函数继续执行。
        
    对于内容比较多的函数, 这点中断时的这点时间开销基本上是可以忽略不计的, 但是当调用十分频繁执行的内容又较少时, 这点时间久不能忽视了, 即便目前的计算机性能越来越好, 但是在能够更快的情况下我们还是尽量让他更快一些。
    
    inline函数的作用就是优化这些将会被频繁调用的函数, 他就相当于把这些inline函数中的函数体直接复制到被调用的函数中一样, 不再使其频繁的中断。 定义inline函数非常简单, 只要在定义时在前面加上 inline 关键字即可, 例如把上面的 输出 10000 次 "Hello, world!" 的程序改成 inline 函数的形式:

 1     #include<iostream>
 2     using namespace std;
 3 
 4     inline void fun()
 5     {
 6         cout<<"Hello, world!\n" ;
 7     }
 8 
 9     int main()
10     {
11         int i ;
12         for(i=0; i<10000; i++)
13             fun() ;             //短时间内将会被调用10000次
14 
15         return 0 ;
16     }

 


    在使用inline函数时需要注意的几点问题:
        1>. inline 函数的函数体语句不适合过多 ;
        2>. inline 函数中不能有 循环、if或switch语句, 否则编译器将会把该函数当做普通函数来处理 ;
        3>. 一个文件中定义的inline函数不能再另一个文件中使用 。
        

 

 

 

四、函数的声明
    在前面的示例中, 我们采取的是直接定义一个函数, 然后再在main函数或其他函数中进行调用, 但是这样做有一个问题, 当函数定义过多, 然后再互相嵌套调用时就非常容易报错, 先看一个示例:

 1     #include<iostream>
 2     using namespace std;
 3 
 4     int main()
 5     {
 6         fun() ;
 7 
 8         return 0 ;
 9     }
10 
11     void fun()
12     {
13         cout<<"Hello, world!\n" ;
14     }


    当我们把fun函数定义在main函数后时, 编译时就会报错: error: 'fun' was not declared in this scope 其意思就是'fun'这个标识符在这个文件中没有声明。或许有些读者会想到, 把函数全部定义在main函数前不就行了吗? 事实并不是这样, 继续看一个示例:

 1     #include<iostream>
 2     using namespace std;
 3 
 4     void fun()
 5     {
 6         cout<<"Hello, world!\n" ;
 7         print() ;       //调用下面的print函数
 8     }
 9 
10     void print()
11     {
12         cout<<"print\n" ;
13     }
14 
15     int main()
16     {
17         fun() ;
18 
19         return 0 ;
20     }


    fun函数和print函数都是在main函数前, 并且fun调用了print函数, 这样便又报错 error: 'print' was not declared in this scope。
    
    要避免这样的错误, 只需要在使用前对函数进行下声明即可, 例如示例一中的代码添加上函数的声明:

View Code
 1     #include<iostream>
 2     using namespace std;
 3 
 4     void fun() ;        //声明fun函数
 5 
 6     int main()
 7     {
 8         fun() ;
 9 
10         return 0 ;
11     }
12 
13     void fun()
14     {
15         cout<<"Hello, world!\n" ;
16     }

  示例二加上声明:

View Code
    #include<iostream>
    using namespace std;

    void fun() ;        //声明fun函数
    void print() ;      //声明print函数

    void fun()
    {
        cout<<"Hello, world!\n" ;
        print() ;       //调用下面的print函数
    }

    void print()
    {
        cout<<"print\n" ;
    }

    int main()
    {
        fun() ;

        return 0 ;
    }


    函数声明类似于函数定义, 只不过没有进行实现, 函数声明是一条语句, 所以要以分号进行结束, 在书写函数声明时, 就像只要把函数头复制下来并在末尾添加上分号即可。
    
    当函数有参数时, 声明时同样要将参数列表一同声明, 例如定义一个max函数, 其中有两个参数:

    void max(int x, int y)
    {
        if(x>y)
            cout<<"max = "<<x ;
        else
            cout<<"max = "<<y ;
    }

    那么在声明时就应该 void max(int x, int y); 不过在声明时编译器并不要求连形参的名称一并声明, 因此上面的声明形式还可以改写为: void max(int, int);

 

 


--------------------


wid, 2013.01.25


上一篇: 学习C++ -> 函数( Function )