C++開發EOS基礎指南:函式引數傳遞
如何將引數傳遞給函式是C++中的一個重要概念。對於初學者來說,這通常很難理解,因為你沒有這些不同的方法來傳遞Java或JavaScript等語言中的引數。你可以通過值呼叫或按引用呼叫將引數傳遞給函式。它們之間的區別在於,在按值呼叫時,會建立實際引數的副本,並且被呼叫的函式在副本上執行。而在通過引用呼叫時,引數的記憶體(地址)中的位置被傳遞給函式。這意味著,該函式將對同一個相同的物件進行操作,因此物件的任何修改都將在函式呼叫之外保留,因為當函式返回時,更改當然不會被還原。我們來看一個例子:
#include <iostream> // this is call by value // the integer x is copied and any modification is done on the copy void test_by_value(int x) { x = 1; } // call by reference is done using the `&` after the type // no copy is created, behind the scenes the memory location is passed // and the same number is used void test_by_ref(int& x) { x = 2; } int main() { std::cout << "Hello World!\n"; int number = 0; test_by_value(number); // outputs 0, number unchaged std::cout << "test_by_value " << number << "\n"; test_by_ref(number); // outputs 2(!), number changed std::cout << "test_by_ref " << number << "\n"; }
請注意,無論你是通過值傳遞還是通過引用傳遞,呼叫者的程式碼都是完全相同的。呼叫者總是隻是傳遞number
。對於引用傳遞,&
符號用作函式引數列表中的指示符。與呼叫方無法區分,因此無法推斷你的資料是否被修改為功能的副作用的一部分。C++有這兩種型別的原因是C++對問題的預設答案:效能。建立大物件的副本需要時間,只需重用現有物件即可避免。你可以通過將引數宣告為const
來禁止修改引數:
int test_by_ref(const int& x) { // this raises a compile time error now // x = 2; // reading is OK return x + 2; }
相同的行為不僅適用於int
,還適用於所有其他資料型別(string
,vector
)和類物件。使用call-by-reference是一種很好的做法,因為它通常更高效,並且不會通過將它們宣告為const
來修改引數。
例如,Google C++樣式指南指出:通過引用傳遞的所有引數必須標記為const
。實際上,Google程式碼中的一個非常強大的約定是輸入引數是值或const引用,而輸出引數是指標。
我們現在理解值和const引用,所以讓我們來談談Google對輸出引數是指標的含義。
指標
指標是儲存另一個變數的記憶體地址的變數。它們在C中被大量使用,因為它沒有按引用呼叫。相反,在C中,你定義一個指標變數,該變數儲存引數的記憶體位置,然後按值傳遞此指標變數。
我們來看看如何在C中編寫測試函式:
int number = 0; // in C++ void test_by_ref(int& x) { x = 2; } test_by_ref(number); // in C void test_by_pointer(int* px) { // remember the value of px is the address of x // to get the actual value of x we need to dereference the pointer by using `*` *x = 2; } // pointers are defined by <type>* // you get the address of a variable by using & int* pnumber = &number; test_by_pointer(pnumber); // or without intermediate pointer variable test_by_pointer(&number);
指向int
變數的指標定義為int *
,指向字串的指標將定義為string *
。 但是,任何指標的實際大小都是相同的:sizeof(int *)== sizeof(string *)
。直觀地,指標可以被視為32位或64位,具體取決於平臺,unsigned int
變數,其值是另一個變數的記憶體地址。
為什麼我們需要指定指標的型別(int *
或string *
)呢?
這是個好問題。嘗試訪問指標指向的變數的值時,型別變得很重要。在我們的例子中,要從int* pnumber
指標獲取number
的值,我們需要取消引用指標。這是由指標變數上的運算子完成的:int numberValue =
pnumber為了知道指標應該讀取多少位元組,我們需要定義指標的型別。
例如,你可以通過執行以下操作逐位元組讀取整數變數:
uint32_t number = 0x01020304; // we need to cast it to uint8_t* because &number is of type unit32_t* // remember the pointers all have the same range as they all store memory addresses uint8_t* p = (uint8_t*)(&number); for(int i = 0; i < 4; i++) { std::cout << "Byte " << i << ": " << std::to_string(*(p+i)) << "\n"; }
如你所見,我們可以對指標進行計算。這稱為指標算術。這裡,*(p+i)
表示在p
的記憶體位置向前移動i
指標型別(sizeof(uint8_t))
的大小,並讀取uint8_t
。
我們還需要C++中的指標嗎?
儘管在C++中使用更簡單的引用references
可以做很多事情,但是在使用迭代器或輸出引數時,你仍會經常遇到指標。輸出引數類似於函式的返回值return
,除了它們作為指標引數傳遞,然後在函式中修改引用的物件。我們來看一個例子:
void split(const std::string &name, std::string *first, std::string *last) { std::size_t pos = name.find(" "); *first = name.substr(0, pos); *last = name.substr(pos + 1); } std::string name = "Dan Larimer"; std::string first, last; split(name, &first, &last);
這裡的first
和last
是指標輸出引數,包含分割功能完成後的計算結果。輸出引數通常用於實際返回引數(string split(...){... return <string>})
,當你需要返回多個值時,就像我們的情況中的兩個string
一樣。
難道我們不能通過使用引用而不是指標作為輸出引數來實現相同的目標嗎?
是的,我們可以重寫函式來使用引用輸出引數:
void split(const std::string &name, std::string& first, std::string& last) { std::size_t pos = name.find(" "); first = name.substr(0, pos); last = name.substr(pos + 1); } std::string name = "Dan Larimer"; std::string first, last; split(name, first, last);
你喜歡什麼取決於你,歸結為個人風格。Google C ++ Styleguide更喜歡將指標作為輸出引數的一個原因是因為它在呼叫者角度看可以清楚地表明該引數可能會發生變化。
然而,能夠閱讀和理解引用和指標是很重要的。
你現在可能會被許多不同的方法傳遞給函式。對於剛接觸C++的開發人員而言,這通常是最大的學習經驗,所以不要擔心。在某些時候,你會看到常見的重複模式。
======================================================================
分享一個互動式的線上程式設計實戰,EOS智慧合約與DApp開發入門 :
ofollow,noindex">EOS教程
本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、賬戶與錢包、發行代幣、智慧合約開發與部署、使用程式碼與智慧合約互動等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。
- java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Java程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
- java以太坊開發教程,主要是針對java和android程式員進行區塊鏈以太坊開發的web3j詳解。
- php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Php程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
- php以太坊,主要是介紹使用php進行智慧合約開發互動,進行賬號建立、交易、轉賬、代幣開發以及過濾器和交易等內容。
- 以太坊入門教程,主要介紹智慧合約與dapp應用開發,適合入門。
- 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
- python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
- C#以太坊,主要講解如何使用C#開發基於.Net的以太坊應用,包括賬戶管理、狀態與交易、智慧合約開發與互動、過濾器和交易等。
匯智網原創翻譯,轉載請標明出處。這裡是原文