Effective C++: Item 24 (轉)
依myan文章中的網址,找到了些資料,故而貼出來,以方便大家!
Item 24: Choose carefully between function overloading and parameter defaulting.
The confusion over function overloading and parameter defaulting stems from the fact that they both allow a single function name to be called in more than one way:
-
void f(); // f is overloaded void f(int x); f(); // calls f() f(10); // calls f(int) void g(int x = 0); // g has a default // parameter value g(); // calls g(0) g(10); // calls g(10)
The answer depends on two other questions. First, is there a value you can use for a default? Second, how many algorithms do you want to use? In general, if you can choose a reasonable default value and you want to employ only a single algorithm, you'll use default parameters (see also Item 38). Otherwise you'll use function overloading.
Here's a function to compute the maximum of up to five int
s. This function uses -- take a deep breath and steel yourself -- std::numeric_limits
as a default parameter value. I'll have more to say about that in a moment, but first, here's the code:
-
int max(int a, int b = std::numeric_limits
::min(), int c = std::numeric_limits ::min(), int d = std::numeric_limits ::min(), int e = std::numeric_limits ::min()) { int temp = a > b ? a : b; temp = temp > c ? temp : c; temp = temp > d ? temp : d; return temp > e ? temp : e; }
std::numeric_limits::min()
is just the fancy new-fangled way the standard C++ library says what C says via the INT_MIN
macro in
: it's the minimum possible value for an int
in whatever compiler happens to be processing your C++ code. True, it's a deviation from the terseness for which C is renowned, but there's a method behind all those colons and other syntactic strychnine.
Suppose you'd like to write a function template taking any built-in numeric type as its parameter, and you'd like the functions generated from the template to print the minimum value representable by their instantiation type. Your template would look something like this:
-
template
void printMinimumValue() { cout << the minimum value representable by T; }
and
. You don't know what T
is, so you don't know whether to print out INT_MIN
or L_MIN
or what.
To sstep these difficulties, the standard C++ library (see Item 49) defines in the header
a class template, numeric_limits
, which itself defines several static member functions. Each function returns information about the type instantiating the template. That is, the functions in numeric_limits
return information about type int
, the functions in numeric_limits
return information about type double
, etc. Among the functions in numeric_limits
is min
. min
returns the minimum representable value for the instantiating type, so numeric_limits
returns the minimum representable integer value.
Given numeric_limits
(which, like nearly everything in the standard library, is in namespace std
-- see Item 28; numeric_limits
itself is in the header
), writing printMinimumValue
is as easy as can be:
-
template
void printMinimumValue() { cout << std::numeric_limits ::min(); }
numeric_limits
-based approach to specifying type-dependent constants may look expensive, but in fact it's not. That's because the long-windedness of the source code fails to be reflected in the resultant code. In fact, calls to functions in numeric_limits
generate no instructions at all. To see how that can be, consider the following, which is an obvious way to implement numeric_limits::min
:
-
#include
namespace std { inline int numeric_limits ::min() throw () { return INT_MIN; } }
INT_MIN
, which is itself a simple #define
for some implementation-defined constant. So even though the max
function at the beginning of this Item looks like it's making a function call for each default parameter value, it's just using a clever way of referring to a type-dependent constant, in this case the value of INT_MIN
. Such efficient cleverness abounds in C++'s standard library. You really should read Item 49.Getting back to the max
function, the crucial observation is that max
uses the same (rather inefficient) algorithm to compute its result, regardless of the number of arguments provided by the caller. Nowhere in the function do you attempt to figure out which parameters are "real" and which are defaults. Instead, you have chosen a default value that cannot possibly affect the validity of the computation for the algorithm you're using. That's what makes the use of default parameter values a viable solution.
For many functions, there is no reasonable default value. For example, suppose you want to write a function to compute the average of up to five int
s. You can't use default parameter values here, because the result of the function is dependent on the number of parameters passed in: if 3 values are passed in, you'll divide their sum by 3; if 5 values are passed in, you'll divide their sum by 5. Furthermore, there is no "magic number" you can use as a default to indicate that a parameter wasn't actually provided by the client, because all possible int
s are valid values for the parameters. In this case, you have no choice: you must use overloaded functions:
-
int avg(int a); int avg(int a, int b); int avg(int a, int b, int c); int avg(int a, int b, int c, int d); int avg(int a, int b, int c, int d, int e);
-
// A class for representing natural numbers class Natural { public: Natural(int initValue); Natural(const Natural& rhs); private: unsigned int value; void init(int initValue); void error(const string& msg); }; inline void Natural::init(int initValue) { value = initValue; } Natural::Natural(int initValue) { if (initValue > 0) init(initValue); else error("Illegal initial value"); } inline Natural::Natural(const Natural& x) { init(x.value); }
int
has to perfoerror checking, but the copy constructor doesn't, so two different functions are needed. That means overloading. However, note that both functions must assign an initial value for the new object. This could lead to code duplication in the two constructors, so you maneuver around that problem by writing a private member function init
that contains the code common to the two constructors. This tactic -- using overloaded functions that call a common underlying function for some of their work -- is worth remembering, because it's frequently useful (see e.g., Item 12). 來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989198/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 學懂現代C++——《Effective Modern C++》之轉向現代C++C++
- effective C++ : CHAPTER 8C++APT
- 【Effective Modern C++】索引C++索引
- Effective C++筆記C++筆記
- effective C++筆記1C++筆記
- 《Effective C++》讀書筆記C++筆記
- Effective C++ 筆記(3)資源管理C++筆記
- Effective C++ 4.設計與宣告C++
- Effective C++ 條款08_不止於此C++
- Effective Modern C++ 系列之 條款2: autoC++
- 《Effective C++》閱讀總結(三):資源管理C++
- 《Effective C++》第三版-1. 讓自己習慣C++(Accustoming Yourself to C++)C++
- 學懂現代C++——《Effective Modern C++》之型別推導和autoC++型別
- 《Effective C++》第三版-5. 實現(Implementations)C++
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- 《Effective C++》閱讀總結(四): 設計、宣告與實現C++
- [讀書筆記][effective C++]條款30-inline的原理筆記C++inline
- 《Effective C++》第三版-3. 資源管理(Resource Management)C++
- JavaScript item()JavaScript
- FileList item()
- 《Effective C++》第三版-4. 設計與宣告(Design and Declarations)C++
- 《Effective C++》閱讀總結(二):類的構造、析構和賦值C++賦值
- sticky list item
- item_get
- 【C++】C++之型別轉換C++型別
- CSSStyleDeclaration.item()方法CSS
- RecyclerView增刪itemView
- 你不知道的JavaScript--Item3 隱式強制轉換JavaScript
- effective java 觀後感Java
- c++ 型別轉換C++型別
- C++圖片格式轉換:BMP轉JPEGC++
- Effective Python學習筆記Python筆記
- 【Effective STL(3)】關聯容器
- 劍指 Offer 24. 反轉連結串列
- 劍指 Offer 24.反轉連結串列
- RecyclerView學習筆記整理(3)解決item中關於跳轉到另一個Activity的問題和判斷多個item進行跳轉到另一個ActivityView筆記
- 24v轉120v,24V轉150v/350v隔離變壓電源模組
- 【轉】C++ static關鍵字C++
- 【C++】禁止隱式轉換C++