反思兩個問題
1. 帶默認參數的函數,為何聲明、定義不能同時有參數?
2. 帶默認參數的函數, 為何帶默認參數的參數靠后站?
上程序
#include <iostream> #include <string> using namespace std; class A { public: A(const string &a = "hello, nihao!", int b = 67); private: string s; int sb; }; A::A(const string &a, int b) : s(a), sb(b) { cout << s << " " << sb << endl; } int main() { string s = "hello"; A a("hello" ,23); }
類A的構造函數,參數帶着默認值,這樣,建立類的對象時可以不給類對象賦全部的參數(沒有的參數會用默認值頂上),這里有幾個個問題:
問題1: 帶參數的構造函數如果聲明時帶上默認的參數,那么在定義時就不能帶了。
這樣設計的目的,我認為是這樣:如果聲明給定了一個參數了,但是定義時又給定了一個不同的參數。這樣,用戶看到的是類的聲明.h文件,但兩者不一樣,會按着定義來。這就給類的使用者帶來了麻煩,因此,為了避免這樣,帶默認參數的函數,兩者只能在一個地方出現,不能同時出現。
其實,不止是構造函數中出現這樣的問題,所有的函數,都應該這樣:聲明和定義的默認默認參數不共戴天----不能同時都有(但是,建議要是有的話,最好在聲明時寫上)。例如:
#include <iostream> #include <string> #include <set> #include <map> using namespace std; class A { public: A(const string &a = "hello, nihao!", int b = 67); void print_A(int a = 34); private: string s; int sb; }; A::A(const string &a = "hello, nihao", int b = 67) : s(a), sb(b) { cout << s << " " << sb << endl; } void A::print_A(int a) { cout << a << endl; } int main() { string s = "hello"; A a("hello" ,23); }
錯誤提示
del7.cc:17:50: error: default argument given for parameter 1 of ‘A::A(const string&, int)’ del7.cc:10:3: error: after previous specification in ‘A::A(const string&, int)’ del7.cc:17:50: error: default argument given for parameter 2 of ‘A::A(const string&, int)’ [-fpermissive] del7.cc:10:3: error: after previous specification in ‘A::A(const string&, int)’ [-fpermissive]
把定義中默認的參數去掉就行了。
問題2. 帶默認參數的函數, 為何帶默認參數的參數靠后站?
我這么理解:從前往后寫,可以少寫,定義對象時,不夠的用默認的參數補上,挺好。反之,如果帶參數的往前寫那么當定義對象時,前邊的有參數,又給傳了實參;而后邊的沒有參數,也不傳,這不浪費嗎。
例證
#include <iostream> #include <string> #include <map> using namespace std; class B { public: B(int c = 5, const string &s = "newfldr") { mapa.insert(make_pair<B*, int>(this, c)); } void print_Bsize() { cout << mapa.size() << endl; } private: static map<B*, int> mapa; }; map<B*, int> B::mapa; //靜態變量,單獨在類外開個小灶 int main() { B b(2, "ni"); B b1(3); //參數預定義不同,因為有默認的參數,沒問題兒 B b2(4, "ni2"); b.print_Bsize(); //因為mapa是類的,所以這里不論是誰,結果都是一樣的 }
結果
3