C++自修入門實境秀、C++ Primer 5版研讀秀 35 ~v6函式-6.4.1. Overloading and Scope
17:30
6.2.5. main: Handling Command-Line Options
6.2.5 main :處理命令列選項
main函式 28:40
main若有參數,其參數傳遞,即是陣列參數的範例。如何將陣列當作引數傳給函式,可藉由mail函式的實作來了解。
3:10
Up to now, we have defined main with an empty parameter list:
int main() { ... }
不帶參數的函式
The most common use of arguments to main is to let the user specify a set of options to guide the operation of the program.
最常見的向mail這個函式傳遞引數的用法,就是讓使用者傳遞一些選項,去引導程式的操作
int main(int argc, char *argv[]) { ... }
arg就是arguments的省略
v,可能就類似vector
第一個參數 argc傳入那個陣列中的字串數。
argc的 c 應是代表count
因為第2個參數agrv是一個陣列,所以完全可以用指針來改寫其函式定義:
int main(int argc, char **argv) { ... }
*argv就等同於一個陣列 argv[]
indicating that argv points to a char* .
表明argv指向一個char*。
指針指向指針,或指向指針的指針
就是指針的指針
When arguments are passed to main , the first element in argv points either to the name of the program or to the empty string. Subsequent elements pass the arguments provided on the command line.
所以這個argv引數在被傳遞時是由第一個元素指向程式的名稱或空字串,而其後的元素則負責承載傳遞了使用者輸入的選項字串。
The element just past the last pointer is guaranteed to be 0.
剛好超過最後一個指標的元素保證是0。
just past the last pointer後位修飾element是怎樣的element(在這裡是指針,因為argv的元素型別是指向C-Style 字元字串的指標(pointer))
這個0應該就是null(\0)
輸入的命令列的值,剛好用半形空格作為argv每個元素的間隔。所以:
Given the previous command line, argc would be 5, and argv would hold the following C-style character strings:
argv[0] = "prog"; // or argv[0] might point to an empty string
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = 0;
最後一個元素保證是0,作為陣列結束的標記(marker)。字元字串有5個,而陣列大小再加1。(最後一個不是字元字串,而是0)
39:18
頁220
練習6.25
40:13
int main(int argc,const char** argv ) //or const char* argv[]
{
cout << endl;
for (size_t i = 0; i != argc + 1; i++)
{
cout << argv[i] << " ";
}
cout << endl;
for (size_t i = 0; i < 5000000000; i++)
{
}
return 0;
1:12:40
練習6.26
6.2.6. Functions with Varying Parameters
6.2.6帶有不定參數的函式
動態參數的函式
不定參數的函式
1:15:30
1:18:30新標準提供了二種定義不定數量的參數函式的方法:
The new standard provides two primary ways to write a function that takes a varying number of arguments:
1.如果所有參數都有一致的型別,則我們可以透過程式庫型別 initializer_list 來傳遞引數
2.如果參數間的型別不一致,則
we can write a special kind of function, known as a variadic template, which we’ll cover in § 16.4 (p. 699 ).
3.C++還有一種特殊的參數型別——ellipsis,
that can be used to pass a varying number of arguments.也可以用來傳遞不定數量的參數
ellipsis parameters
這種機制(運用)應該只在需要與C語言的函式作互動的時候才用上
值得注意的是,這項機能通常只應該用於需要與C 函式界接的程式中。
1:29:33
initializer_list Parameters
前提是要參數型別一致
1:37:00
copy or assign initializer_list 並不copy 來源的元素,而是與來源共享其元素
1:39:00
頁221
initializer_list 和 vector類似,皆為 template type(模板型別)
與vector不同的是,initializer_list 中的元素值皆是const常值:
Unlike vector , the elements in an initializer_list are always const values; there
中文版又翻錯了吧:
our debugging system might have a class, named ErrCode , that represents various kinds of errors.
我們的除錯系統可能會有一個類別、具名的錯誤碼ErrCode用來代表各種錯誤。
我們的除錯系統可能會有一個類別——叫做ErrCode——用來代表各種錯誤。
具名的錯誤碼ErrCode→叫作「ErrCode」,指這個類別叫作「ErrCode」
2:00:20
頁222
Ellipsis Parameters
Ellipsis 參數
varargs
varying arguments
ellipsis參數只能出現在參數列的末後(殿後),可以有2種表達式:
void foo(parm_list, ...);
void foo(...);//真按:只有一個的話,它當就是最後一個了
2:8:00真的就是刪節號(即3個句號或小數點)
對應到ellipsis參數的引數不會做型別檢查。
2:14:00
In this first form, the comma following the parameter declarations is optional.
在這第一個形式中,接在參數宣告後的逗號是選擇性的。
意思就是 void foo(parm_list, ...); 可以寫成:
void foo(parm_list ...);//省略掉逗號
練習6.27
2:16:55
2:36:30
void print_sum_of_the_elements_in_the_list(initializer_list<int> lst)//練習6.27
{
int sm=0;
for (auto l : lst)
sm += l;
cout << sm << endl;
}
int main(int argc, const char** argv)
{
print_sum_of_the_elements_in_the_list({ 11,2,3 });
return 0;
}
函式在標頭檔的宣告和在源碼檔的定義,依然搞不清楚是錯在哪裡了。如上式不在標頭檔裡宣告,就不會出錯。
練習6.28
參考(reference)型別
練習6.29
2:41:05
應該是不能用參考(reference)型別作 initializer_list range for的控制變數,因為 initializer_list中的每個元素都是const常值,而用參考(reference),通常是要改寫所參考對象的值。所以要用,也要加上const 免得在初始化參考時,會多有限制(如不能用const值來初始化一個非const的參考)
2:46:30
6.3. Return Types and the return Statement
6.3回傳型別與return述句
A return statement terminates the function that is currently executing and returns control to the point from which the function was called.
頁223
6.3.1. Functions with No Return Value
In a void function, an implicit return takes place after the function’s last statement.
所以看似不回return,實際上是仍有一個隱含的 return在執行(發生),在函式主體的最後一個述句執行之後。
一個void的函式如果想在半途退出的話,可以在其中插入retrun述句。
2:58:30
6.3.2. Functions That Return a Value
6.3.2回傳一個值的函式
頁224
3:7:00
// error #2: control might flow off the end of the function without a return // the compiler might not detect this error
函式可能執行完了卻沒有觸發任何的return述句,而此函式是要傳回bool值的。這種錯誤是編譯器未必會偵測到的
cxecution就是 control flow
Failing to provide a return after a loop that contains a return is an error.
在一個包含了return述句的迴圈之後忘了為函式提供一個return述句,決定是錯誤的;而這種錯誤,對於絕大多數的編譯器,都是無法偵測到的。
How Values Are Returned
值是如何回傳的?
函式值是怎樣被傳回的
如何傳回一個函式值
暫存物件(temporary)
3:24:00
It is important to keep in mind the initialization rules in functions that return local variables.
狠重要的一點是要牢記會回傳區域變數的函式中的初始化規則。
也就是在函式內的區域變數要定義為參考(reference)型別才能回傳該區域變數到函式外
(函式之參數也屬區域變數)
3:35:30
頁225
Never Return a Reference or Pointer to a Local Object
永遠都不要回傳對區域物件的參考或指標
3:47:10
Tip
One good way to ensure that the return is safe is to ask: To what preexisting object is the reference referring?
確保return是安全的一個好方法是質問:參考指涉到什麼現有(preexisting)物件?
總之,要隨時留意參考到底是參考誰,是誰的別名。如果是一個無效的對象(object)當然就不能使用了。
Functions That Return Class Types and the Call Operator
傳回類別型別(class type)的函式,以及傳呼運算子(呼叫運算子、調用運算子)
回傳類別型別的函式與呼叫運算子
頁226
3:59:00
Reference Returns Are Lvalues
回傳的參考是Lvalue
⑧找對主詞 Reference Returns 是複數,所以用「Are」,而受詞也是複數「Lvalues」
∴ Reference Returns 是一個複合名詞
只要函式傳回值的型別是參考(reference),那這個回傳值就是左值,否則就是右值。
回傳值為參考的函式有如下介面(函式介面)
傳回型別& 函式名稱();
傳回型別末綴一個「&」就是指回傳對該型別的參考
4:18:00
List Initializing the Return Value
串列初始化回傳值
串列初始化(list initialization)回傳的值
已經被串列初始化的回傳值
將回傳的值串列初始化 4:28:20
因為串列初始化(list initialization)通常是來初始化陣列或container(ex. vector),所以我們可以定義一個回傳值型別為vector的函式
頁227
如果一個函式傳回的值是內建型別,那麼串列初始化(list initialization)這個值的串列,就只能是空串列或僅僅一個元素的串列,而且也不能被截斷(narrowing conversion):
In a function that returns a built-in type, a braced list may contain at most one value, and that value must not require a narrowing conversion (§ 2.2.1 , p. 43 ).
在回傳內建型別的函式中,一個大括號圍起的串列至多可以含有一個值,而那個值必定不能 需要變窄的轉換(narrowing conversion,§ 2.2.1)。
4:41:10
Return from main
從main回傳
4:44:00
The main function is allowed to terminate without a return. If control reaches the end of main and there is no return, then the compiler implicitly inserts a return of 0.
mail函式可以允許不回傳值
control ⑦先抓動詞 這裡是名詞,相當於execution
原來編譯器會自動為mail函式插入一個0的回傳值 4:51:00
main傳回0則表示應用程式執行成功,否則多表示有問題:
A zero return indicates success; most other values indicate failure.
mail預設的回傳值是由機器決定的,而
cstdlib header defines two preprocessor variables (§ 2.3.2 , p. 54 ) that we can use to indicate success or failure:
cstdlib這個標頭檔定義了兩個預處理式(前置處理器 preprocessor)變數,讓我們可以用來作為main要傳回值(執行是成功或失敗的訊息):
int main()
{
if (some_failure)
return EXIT_FAILURE; // defined in cstdlib
else
return EXIT_SUCCESS; // defined in cstdlib
}
預處理式(前置處理器 preprocessor)變數,不能使用在using宣告中,也不能前置「std::」(命名空間)
前面學過的是「NULL」
5:21:00
在VisualStudio 2019搜尋內容
Code, Recent Items, and Template Search In Visual Studio
Recursion
遞迴(Recursion)
大陸翻「遞歸」, 迴、歸 ②單字想複詞 → 北迴歸線
就是自己呼叫自己的函式:
A function that calls itself, either directly or indirectly, is a recursive function .
不管是直接還是間接地
// calculate val!, which is 1 * 2 * 3 . . . * val
int factorial(int val)
{
if (val > 1)//這就像迴圈的條件式
return factorial(val - 1) * val;//自己呼叫自己的遞歸遞迴(recursion)就像迴圈,所以都有「迴」字
return 1;
}
In this implementation, we recursively call factorial to compute the factorial of the numbers counting down from the original value in val . Once we have reduced val to 1 , we stop the recursion by returning 1 .
在這個實作中,我們會遞迴地呼叫factorial來計算從val中原本的值往回數的數字之階乘。一旦我們將val縮減為1,我們就回傳1來停止遞迴。
一旦我們將val縮減為1→一旦我們將val減到1
可見寫一個具體的、可執行的程式,就是實作(implemetation)
5:20:00
until the program stack is exhausted.
stack ovrflow 5:22:30
5:21:30
頁228
Such functions are sometimes described as containing a recursion loop .
可見遞歸(recursion)遞迴和迴圈脫不了干係
In the case of factorial , the stopping condition occurs when val is 1 .
可見還是有條件式,來決定迴圈的退出時機
main 函式是不能作遞迴(recursion)的
5:35:50
練習6.30
error C2561: 'str_subrange': function must return a value
5:42:59
練習6.31
函式要傳回參考,須注意參考的對象(object)是否還有效,此對象的生命週期必須能跨出該函式才可以,決定不能是區域變數。
對const的參考和plain參考也一樣,只是傳回的值不能被修改或指定而已
練習6.32
5:46:50
5:57:20好像哪裡有講過,陣列都是傳址的,因為陣列不能被拷貝。所以對陣列的處理實際上都是在處理指標。在此例中,陣列ia是藉由傳址方式傳入get函式的
6:11:20
練習6.33
vector<string>::const_iterator print_vector(vector<string>::const_iterator vsi, vector<string>::const_iterator visend) {
cout << *vsi << " ";
++vsi;//要寫一個遞迴(recursion)應該是先寫好函式的本體,再呼叫它本身的遞迴部分邏輯才清楚,不會紊亂、打結 6:37:00
if (vsi != visend) {
return print_vector(vsi, visend);//其實遞迴(recursion)就是寫一個非while do_while for的迴圈嘛
}
cout << endl;
return vsi;
}
int main() {
vector<string> vs{"王之渙","登鸛雀樓","白日依山盡","黃河入海流","欲窮千里目","更上一層樓"};
print_vector(vs.begin(),vs.end());
}
練習6.34
6:48:30 結果是一樣的
練習6.35
6:51:28 6:57:30 因為val本身值會變,就會影響「*val」(乘以val)運算的結果
用「val --」會變成無窮迴圈,用「--val」則會變成乘以0。(因為最後一個!=0條件後,val的值又被--val計算了一次,而被改變了)
7:6:10
6.3.3. Returning a Pointer to an Array
傳回一個指向陣列的指標(pointer)
6.3.3回傳對陣列的一個指標
陣列是不能被拷貝的:
Because we cannot copy an array, a function cannot return an array. However, a function can return a pointer or a reference to an array (§ 3.5.1 , p. 114 ).
Because we cannot return an array, we define the return type as a pointer to this type.(頁229)
7:17:01
Unfortunately, the syntax used to define functions that return pointers or references to arrays can be intimidating. Fortunately, there are ways to simplify such declarations. The most straightforward way is to use a type alias (§ 2.5.1 , p. 67 ):
遺憾的是,用來定義會回傳對陣列的指標或參考的函式之語法可能令人望而生畏。幸好,有簡化這種宣告的方式存在。最直接明瞭的方法是使用一個型別別名(type alias,§2.5.1):
不幸的是,傳回對陣列的指標或參考的函式的語法是很嚇人的
typedef 7:21:11 型別的別名
頁229
7:22:10 func就是function的省稱
typedef int arrT[10]; // arrT is a synonym for the type array of ten int s
using arrT = int[10]; // equivalent declaration of arrT ; see § 2.5.1 (p. 68)
arrT* func(int i); // func returns a pointer to an array of ten int s
arrT應是arrayType(陣列型別)的縮語
像在繞口令一樣,繞一圈來寫
typedef int arrT[10]
一般不是陣列型別(型態)時是寫成:
typedef int arrT,就是用 arrT作為int型別的別名
typedef和using…=…的語法,二個「受詞」剛好一前一後顛倒
Declaring a Function That Returns a Pointer to an Array
宣告一個傳回對陣列指標的函式
宣告會回傳對陣列指標的函式
7:35:00
如果不要用別名來宣告一個會回傳對陣列的指標的函式,那麼就要如此宣告:
type (*name(parameter list))[dimension]
Type ( * function ( parameter_list ))[ dimension ]
7:43:28
已看完Google Play圖書的試讀部分
開始購買
7:48:05 購買完成
7:52:00
• (*func(int)) says we can dereference the result of that call.
• (*func(int))[10] says that dereferencing the result of a call to func yields an array of size ten.
所以「*」asterisk星號在定義或宣告中一樣具有解參考(dereference)之義也。
7:55:50
Using a Trailing Return Type 在函式宣告的尾端指名回傳型別
使用尾端回傳型別(Trailing Return Type)
就是因為要回傳的型別指定是綴在宣告的尾端,所以叫做尾端回傳型別:
auto func(int i) -> int(*)[10];
而因為末尾已經指定,故函式介面前端的回傳型別處,就用auto,而不指名:
為了表明回傳之型別已標明在參數串列後,所以我們用auto寫在通常一個函式要指名回傳型別的地方:
To signal that the return follows the parameter list, we use auto where the return type ordinarily appears:
為了表明回傳跟在參數列後,我們在回傳型別一般出現的地方使用auto :
8:43:00 ∴ trailing return 可以翻成尾端指名回傳型別
頁230
Using decltype
用decltype來定義函式回傳型別,有先決條件制:8:41:00
As another alternative, 作為一個替代方案if we know the array(s) to which our function can return a pointer, we can use decltype to declare the return type. 如果我們知道我們想要回傳的指標時指向怎樣的陣列的話,我們就可以用decltyp去宣告函式的回傳型別
如果不知道不就行(用decltype此法)
For example, the following function returns a pointer to one of two arrays, depending on the value of its parameter:
8:11:00
在decltype的運算中並不是把陣列自動轉成指標。可見decltype判斷的、回傳的會是精確的型別,不是隱含轉型後的(如「整數提昇」,應也不會在此作用)
8:17:40
練習6.36
8:42:00
without using either a trailing return, decltype , or a type alias.
可見總共有4種方式可以定義函式的回傳型別(尤其是複雜型別,如參考、指針):
1.尾端指名回傳型別
2.當知道要回傳的是怎樣的陣列時 用decltype()
3.型別別名 typedef 原名 別名 或
using 別名=原名
const string(&arrStr10( const string (& arrstr10)[10]))[10]
{
const string (& arrref)[10] = arrstr10;
return arrref;
}
int main() {
string arrstr10[10]{ "忠","孝","仁","愛","信","義","和","平","禮","義" };
for (string s:arrStr10(arrstr10))
{
cout << s << endl;
}
}
練習6.37
8:48:20
typedef或using = 要寫在函式外(之前)
typedef string arrT[10];// using arrT=string [10];
const arrT& arrStr10_type_alia(const string(&arrstr10)[10])
{
const string(&arrref)[10] = arrstr10;
return arrref;
}
int main() {
string arrstr10[10]{ "忠","孝","仁","愛","信","義","和","平","禮","義" };
for (string s:arrStr10_type_alia(arrstr10))
{
cout << s << endl;
}
}
9:2:24
9:4:29
decltype(expr)的expr也要在函式外(之前)
string arrstr10[10]{ "忠","孝","仁","愛","信","義","和","平","禮","義" };
const decltype(arrstr10)& arrStr10_decltype(const string(&arrstr10)[10])
{
const string(&arrref)[10] = arrstr10;
return arrref;
}
int main() {
for (string s: arrStr10_decltype(arrstr10))
{
cout << s << endl;
}
}
9:12:58
auto arrStr10_trailing_return(const string(&arrstr10)[10])->const string (&)[10]
{
const string(&arrref)[10] = arrstr10;
return arrref;
}
int main() {
string arrstr10[10]{ "忠","孝","仁","愛","信","義","和","平","禮","義" };
for (string s: arrStr10_trailing_return(arrstr10))
{
cout << s << endl;
}
}
9:17:10
練習6.38
int odd[] = { 1,3,5,7,9 };
int even[] = { 0,2,4,6,8 };
// returns a pointer to an array of five int elements
decltype(odd)& arrPtr(int i)
{
return (i % 2) ? odd : even; // returns a array to which the ref refer 傳回的參考就是此二陣列的別名
}
int main() {
for (int i: arrPtr(1))
{
cout << i << endl;
}
}
9:24:50 9:28:30
6.4. Overloaded Functions
6.4重載的函式
所以多載的函式不是同名而參數串(參數列、參數串列parameter lists)不同就好,還要在同一個scope中才行。
9:32:10
頁231
the compiler can deduce which function we want based on the argument type we pass:
Function overloading eliminates the need to invent—and remember—names that exist only to help the compiler figure out which function to call.
函式重載讓我們不用發明和記住只為了輔助編譯器找出要呼叫誰而存在的那些名稱。
函式的重載(overload)讓我們省去只為了讓編譯器了解我們確實要調用哪一個函式,而去編/湊一個新的函式名稱(甚至還得去記住它),好讓編譯器能夠找到這個函式來調用
invent意指另立一個名稱。此處翻成「發明」就不適當;在中文語境下無法達意也。
函式重載(overload)的目的就是幫助我們不必為了類似的工作或目的,而只是要傳的引數不同,而另外再取許多不同的函式名稱,只為了避免名稱重複,讓編譯器好認得出來。
9:49:50
就如main 沒有遞迴(recursion)一樣,main也不能重載(overload)
遞迴和重載都可看作時「分身」的意思
而main是整個應用程式中獨一無二的特殊函式(乃應用程式的執行切入點),故均不可遞迴與重載(overload)多載。
9:52:10
Defining Overloaded Functions
定義重載函式
10:6:00
Determining Whether Two Parameter Types Differ
判斷兩個參數型別是否不同
判斷兩個參數的型別是否有不同
10:8:5
參數名稱是可以省略的
只要效益function上一樣的參數列,都是齊等的(identical)。不取於相!不著文字相
不要被它表面的樣子騙了
頁232
10:12:00
In the first pair, the first declaration names its parameter.
⑦先抓動詞 names
Parameter names are only a documentation aid.
參數名稱只有說明文件的效果。
⑧找對主詞 names
那麼說來,參數名就若程式碼的註解了嘛
Overloading and const Parameters
重載與const參數
多載與常值參數
一個含有頂層常值const的參數和一個沒有的,並無法分別的
A parameter that has a top-level const is
indistinguishable from one without a top-level const:
具有頂層const的一個參數與沒有頂層const的參數之間是無法區辨的
10:20:40
重新宣告
→重覆宣告。因為頂層的const會被省略,就無法區別
所以頂層的常值是不能重載(overload)的,而底層的可以
10:22:20
10:27:00
因為隱含換沒有const作為來源的,只有const作為目的的(頁162)所以若傳遞一個常值的引數,或指向常值的指針,只能由參數為對常值的指針或常值的參數來接收這樣的引數
10:34:39
const_cast and Overloading
常值轉型與多載
const_cast 與重載
11:16:20 因為底層的const會造成不同的函式(多載),所以const_cast才與多載有了關係、發生意義
10:39:20
頁233
Advice: When Not to Overload a Function Name
建議:何時不要重載一個函式名稱?
建議或忠告
考慮重載(overload)函式的必要
何時不須去重載(overload)函式
要考慮,重載是否有必要
一個適合的切入點去思考,就是,呼叫端在調用這個函式時,讀者是否容易從其呼叫函式的述句裡看出要做什麼事的端倪。如果辨識力不足,就應該考慮把函式的名稱取清楚點,才比較好
There are some cases where providing different function names adds information that makes the program easier to understand.
在某些情況中,提供不同的函式名稱確實可以增加資訊,使得程式更容易理解。
⑦先抓動詞 adds ⑧找對主詞 providing different function names
確實有時候,提供不一樣的函式名稱(有識別力的函式名稱)會提供額外的資訊讓整個程式讀來更為容易些
11:17:49
Calling an Overloaded Function
呼叫一個重載的函式
呼叫多載函式尤其是視其所傳的引數型別來決定是調用哪一個函式
11:22:20
Function matching (also known as overload resolution ) is the process by which a particular function call is associated with a specific function from a set of overloaded functions.
函式匹配(Function matching,也稱作重載解析,overload resolution)就是一個特定的函式呼叫與一組重載的函式中特定的一個產生關聯的過程。
11:25:00
頁234
11:34:40
The compiler finds exactly one function that is a best match for the actual arguments and generates code to call that function.
⑧找對主詞 generates的主詞是The compiler
⑥相對位置有相關字義 finds…and genrates…
11:39:50
練習6.39
(a)
int calc(int, int);
int calc(const int, const int);
重覆宣告了
具有頂層const的一個參數與沒有頂層const的參數之間是無法區辨的:(頁232)
(b)
int get();
double get();
只有傳回型別不同,不可多載
兩個只差在回傳型別的函式是錯誤的。如果兩個函式的參數列相同,但回傳型別不同,那麼 第二個宣告就會是個錯誤:(頁231)
(c) 11:46:00
int *reset(int *);
double *reset(double *);
參數的型別不同,合法的多載(可見與傳回型別無關,只要參數型別不同即可多載)
11:48:48
6.4.1. Overloading and Scope
多載和範疇
6.4.1重載與範疇
12:5:00這裡其實要討論的是在不同scope中同名的實體(entity)是否具有重載的關係。在C++中,其實內層的同名物會覆蓋、覆寫或遮蔽(hide)外層的同名物,所以並不具備多載的機會
11:55:00
函式多載的前提就是the same scope
可見practice是翻作習慣或慣例、常例、常規的。所以本書的best practices翻成養成好習慣是最適當不過的了
區域性的宣吿一個函式都是壞主意。
→區域性地宣吿一個函式是不好的。
12:2:20
重載(overload)是不能跨範疇(scope)的:
Names do not overload across scopes:
不同範疇的同名實體(entity)是不會被重載的
頁235
12:1:00 區域中定義的同名物件,會遮蔽(hide)所有外層的同名物件。
有點像 override(覆寫)
visible(有效)對 hide(無效—被遮蔽了、覆寫了)
note:
In C++, name lookup happens before type checking.
C++編譯的順序是先找識別項名稱,再核對型別(再做型別檢查)。名稱都找不到,當然就不必核對型別了
頁236
6.5. Features for Specialized Uses
6.5特殊用途的功能
留言