C++ 中的函式與數學中的函數有些類似,但也卻存在一些差異。事實上,先前我們的程式碼就包含惹 main() 這個最基本的函式。撰寫程式的過程中,如果有某些片段經常重複使用,或是有其他需求比如強調或是遞迴,就可以考慮宣告成函式。

#include <iostream>

using namespace std;

long long foobar(int x)
{
    return 1LL * x * x;
}

int main()
{
    cout << foobar(87) << '\n'
         << foobar(69) << '\n';
    return 0;
}

上例中,我們宣告一個名為 foobar() 的函式,其回傳型別為 long long, 並接受一個 int 的參數。當然,實務上的函式往往複雜許多,可以包含輸出、條件分支、迴圈控制、呼叫其他函式,能做的事就跟以前我們在 main() 做的一樣,甚至還可以呼叫自己。比較特別的是,函式可以沒有參數,還可以沒有回傳值,即回傳型別為 void.

參數的傳遞#

#include <iostream>

using namespace std;

void foobar(int x)
{
   x = 69;
}

int main()
{
    int x = 87;
    foobar(x);
    cout << x << '\n';
    return 0;
}

如果你覺得是 \(69\), 恭喜答錯惹。原因是,C++ 在呼叫函式時,預設是將參數的值複製過去,也就是說,foobar() 中的 xmain()x 可謂風馬牛不相及。那如果我們真的有需要在 foobar() 修改 main()x 要怎麼辦呢??還記得先前介紹的指標與參考嗎??

Call by Value#

#include <iostream>

using namespace std;

void foobar(int x)
{
    cout << &x << '\n';
    x = 69;
}

int main()
{
    int x = 87;
    cout << &x << '\n';
    foobar(x);
    cout << x << '\n';
    return 0;
}

就是預設情形,foobar()x 是拷貝的副本。

Call by Pointer#

#include <iostream>

using namespace std;

void foobar(int *ptr)
{
    cout << ptr << '\n';
    *ptr = 69;
}

int main()
{
    int x = 87;
    cout << &x << '\n';
    foobar(&x);
    cout << x << '\n';
    return 0;
}

如果使用指標,我們就可以在 foobar() 修改 main()x, 但要留意 &, * 的語法。

Call by Reference#

#include <iostream>

using namespace std;

void foobar(int &x)
{
    cout << &x << '\n';
    x = 69;
}

int main()
{
    int x = 87;
    cout << &x << '\n';
    foobar(x);
    cout << x << '\n';
    return 0;
}

參考的版本給你參考。

函式指標#

什麼!?指標已經夠討厭惹,函式還有指標啊??是的,依照 von Neumann 架構,函式在被執行前需要先被載入記憶體,有惹記憶體位址當然就有指標。詳細情形等以後提到函式物件在說個清楚吧。

#include <iostream>

using namespace std;

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

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

int main()
{
    void (*func)() = foo;
    func();
    func = bar;
    func();
    return 0;
}