函數參數傳遞本質上是主調函數與被調函數之間的通訊方式。主要有兩種基本機制:值傳遞 與 引用傳遞。
C 語言只有值傳遞。許多人誤以為傳遞指標是引用傳遞,實則不然——指標變數的值(即位址)被複製傳遞。
void swap(int *x, int *y) {
int temp = *x; *x = *y; *y = temp;
}
void main() {
int a = 1, b = 2;
int *p1 = &a, *p2 = &b;
swap(p1, p2); // 傳遞指標的「值」(位址),屬值傳遞
}
關鍵觀念:
C++ 提供三種參數傳遞方式:
另有全域變數傳遞(廣義上包含類別成員變數、static 變數、namespace 限定變數),效率最高但不支援多執行緒,工程上應謹慎使用。
// 傳值:無法修改實參
void swap(int a, int b) { int t=a; a=b; b=t; }
// 傳指標:可修改實參
void swap(int *pa, int *pb) { int t=*pa; *pa=*pb; *pb=t; }
// 傳引用:可修改實參,語法更直觀
void swap(int &ra, int &rb) { int t=ra; ra=rb; rb=t; }
值傳遞在函數體內採直接定址,指標/引用採間接定址。若函數體內頻繁操作參數,間接定址會造成明顯效能損失。
void* 幾乎無檢查,易產生 Bug。若形參為父類別、實參為子類別,值傳遞會導致物件切割——僅建構父類別部分,失去子類別特有行為(虛函式無法正常運作)。此時必須用指標或引用。
值/引用傳遞無法傳遞「不存在的值」;指標可能傳遞野指標、懸空指標。健壯程式碼優先使用值或引用傳遞。
指標可傳遞 nullptr 表示「無物件」,標準庫 time() 即利用此特性。此為指標獨有優勢。
const T&),兼顧效率與安全。nullptr)。輸入參數加 const 防止誤修改,也是文件化介面意圖:
int strlen(const char *str); // 承諾不修改 str 指向的資料
int strlen(const char *const str); // 連指標本身也不允許修改(較少見)
成員函數後加 const 表示不修改物件狀態:
class Person {
unsigned char age() const; // 僅讀取 m_age
unsigned char m_age;
};
減少多載函數數量,但 C# 移除此特性(安全考量),使用時需謹慎。
同名函數的共同參數盡量置於相同位置,方便呼叫端。
void swap(const int& x, const int& y); // 函數體內無法修改 x、y