看板 C_and_CPP 關於我們 聯絡資訊
分享一下自己看到這題目會怎麼寫 ※ 引述《o07608 (無良記者)》之銘言: 怒刪 : 請撰寫一組equal()的多載函式, 看到以上這一句就可以知道題目是要你寫好幾個像這樣的function: ? equal(?) 每一個都叫equal,但是傳入的參數每個會不太相同, (這就是C++的function overloading的概念) : 能接受兩個相同型態的引數,若兩者相同則傳回1,否則傳回0。 這裡只有說要傳回0或1,並沒有說型態為何,就先假定是bool吧,所以我們要寫好幾個: bool equal(?) : 提供的版本有:char、int、double、char*等型態的引數。 要寫四個equal,加上前面提到"能接受兩個相同型態的引數",推導出要寫的就是: bool equal(char, char); bool equal(int, int); bool equal(double, double); bool equal(char*, char*); 俗話說:把signatures寫出來,就已經寫完一半了(咦?有這句嗎?) 把function的type寫出來之後,其實要做啥就很清楚了, 如果你拿到兩個char、兩個int或是兩個double, 要如何生出一個bool表示他們是否相同?這你第一天學C就會了,瞬間秒殺: bool equal(char a, char b) { return a == b; } bool equal(int a, int b) { return a == b; } bool equal(double a, double b) { return a == b; } (註1) : 使用strcmp()函式來測試字串是否相同 char*本身是pointer,你如果直接用==比較大小,其實是比較pointer的值, 也就是字串頭的記憶體位置,而不是真正比較字串的內容,所以要用strcmp, 至於strcmp要怎用?如果不知道或忘了就去查啊XD http://en.cppreference.com/w/cpp/string/byte/strcmp 這裡他說strcmp吃兩個const char* lhs和rhs,如果lhs和rhs一樣就return 0, 所以我們當然就是把兩個字串傳給strcmp,然後看看結果是不是0, bool equal(char* a, char* b) { return strcmp(a, b) == 0; } 這樣其實就已經把題目要求的寫完了,剩下就寫些test case看看對不對(註2): #include <cassert> int main() { assert(equal('a', 'a') == true); assert(equal('a', 'b') == false); assert(equal(1, 1) == true); aseert(equal(1, 0) == false); assert(equal(1.0, 1.0) == true); assert(equal(1.0, 2.0) == false); char* foo1 = new char[4]; // (註3) strcpy(foo1, "foo"); char* foo2 = new char[4]; strcpy(foo2, "foo"); // Make sure foo1 and foo2 point to different address so that // equal will fail if it only compares pointer address. assert(foo1 != foo2 && equal(foo1, foo2) == true); assert(equal(foo1, "bar") == false); delete [] foo1; delete [] foo2; return 0; } 至於你問輸入的部份其實和題目就已經沒有相關了,這部份還有很多東西可以探討XD 如果你只是要交作業/應付工作,寫到這邊其實你就可以交差了, 不過如果C++只有這樣我也必要在這邊發廢文了,bjarne也要準備回家吃自己了... Const-correctness 首先C和C++裡面有一個非常重要的概念是const,它基本上有兩個含意: 1. 如果你宣告一個value為const,代表它的值不會被改變 2. 如果你宣告pointer或reference指向的東西為const, 代表你不會透過這個pointer和reference去修改它(註4) 在參數和變數上適當宣告const可以幫助你避免很多錯誤, 在equal(char*, char*)之中,其實我們只是要透過這個指標看看值一不一樣而已, 並沒有打算要改它,因此我們應該宣告它為equal(const char*, const char*), 除了避免我們不小心在函數內修改到它之外,更重要的是告訴這個function的caller\ 你把pointer傳給我,我不會去亂改它指向的東西,這對caller來說很重要, 因為如果caller拿到一個const char*的話,它只能傳給其他接受const char*的函數, 而不能傳給接受char*的函數,否則就變成caller說謊, 它先說說我不會去改它(const char*),然後又偷偷叫別人去改它(用char*傳給別人) Template 再來可以注意到char、int和double這三個版本其實除了型態以外,其他全部都一樣, 這就是function template可以幫忙的時候了,把一樣的型態抓出來: template<typename T> bool equal(T a, T b) { return a == b; } compiler就會依照你傳入的參數不同,自動幫你生出對應的版本, 無論T是char、int、float、double、long long、const char*或std::string, 反正只要T可以用==來比較就可以了,然後等等...^^^^^^^^^^^這是什麼東西? 前面好像有提到const char*不能直接用==比,這樣生出來的不就不對了嗎? 還好C++有規範:當function template和你寫的function都存在的時候, 會選擇去先去試試看呼叫你特地寫的function,所以: equal("foo", "bar"); template<typename T> bool equal(T a, T b) { return a == b; } bool equal(cosnt char* a, const char* b) // 你自己寫的ordinary function { return strcmp(a, b) == 0; } 雖然把const char*帶入T也可以,但是compiler會選擇你寫的版本, 所以就變成先寫一個最general的版本,再針對特殊case做處理(註5) 當然,以上的template還只是最基本的版本,還有很多延伸的問題可以討論, 例如上面是用call-by-value,如何用call-by-reference避免複製大型物件, 而又要保持primitive type (如int)仍然是pass-by-value,要怎樣寫最general? (hint:用boost::call_params、std::enable_if...等) 當然如果你初學可以先跳過這些,等熟悉以後再回來看 心血來潮寫了這麼多但是好像沒啥重點(?),就加減看看吧XD 附註 1. float或double直接用==比較會有precision的問題 2. 這就是偽TDD,應該要先寫test case出來XD 3. 不要用new,用std::unique_ptr<char[]>或std::string幫你自動管理記憶體 4. 很多人認為const T*或const T&代表它指向的值不會變,但事實上這觀念是錯的, 它只有說你不會透過這個pointer或reference來改變它而已, 也因為這誤解造就出了無限多的bug和漫罵,詳見:http://goo.gl/IJPBJ 5. 不是function template specialization,C++是沒有這種東西的, 如果你要特製化function,直接寫一個overloaded function, 在overload resolution的時候就會幫你解決掉 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.113.235.102 ※ 編輯: PkmX 來自: 140.113.235.102 (01/26 23:45) ※ 編輯: PkmX 來自: 140.113.235.102 (01/26 23:45)
loveme00835:4. 還有thread safe的含意, 詳見 http://ppt.cc/wGdp 01/26 23:49
loveme00835:5. name mangling 還是不同的, 皆可呼叫時還會有優先 01/26 23:51
loveme00835: 的考量 01/26 23:51
o07608:這怎麼可能只是加減看的等級......Q_Q 01/27 00:03
loveme00835:像 P 大一樣有熱情就會學很快了~ 01/27 00:06
dendrobium:浮點數根本就不該用==, 不是'比較' 01/27 00:21
PkmX:樓上: 我的意思是"用==比較"不是"比較有問題" XD 01/27 00:50
EdisonX:equal('a','a') 是呼叫 int 版 ? 01/27 01:09
EdisonX: ^嗎 ? 01/27 01:10
EdisonX:sorry, 請無視樓上堆文 @@ 01/27 01:13