|
|
1.功能:創(chuàng)建(build objects)對象,將一連串的隨意的內(nèi)存位變對象,也分配資源(memory, files, semaphores, sockets等),"ctor" 是構(gòu)造函數(shù)(constructor)典型的縮寫。 2.假定List是個類名,List x和 List x()的區(qū)別:前者聲明了一個List對象,后者則是一個函數(shù),返回List類型。 3.能否在一個構(gòu)造函數(shù)中調(diào)用另一個構(gòu)造函數(shù)?答案是否定的。 假設(shè)類Fro有兩個構(gòu)造函數(shù)Foo::Foo(char x)和Foo::Foo(char x,int y),那么下面的代碼 class Foo { public: Foo(char x); Foo(char x, int y); ... }; Foo::Foo(char x) { ... Foo(x, 0); // this line does NOT help initialize the this object!!to initialize a temporary(臨時量), local object (not this), it immediately destructs that temporary when control flows over, ... } 也可以組合這兩個構(gòu)造函數(shù),通過默認(rèn)參數(shù) class Foo { public: Foo(char x, int y=0); // this line combines the two constructors ... }; 如果沒有默認(rèn)參數(shù)可用,那么我可以共享公用代碼在私有的Init函數(shù)中,如: class Foo { public: Foo(char x); Foo(char x, int y); ... private: void init(char x, int y); }; Foo::Foo(char x) { init(x, int(x) + 7); ... } Foo::Foo(char x, int y) { init(x, y); ... } void Foo::init(char x, int y) { ... } 不要嘗試把它用在布局new(placemement new)中,有些人認(rèn)為可以new(this) Foo(x, int(x)+7)在Foo::Foo(char)中,這是絕對錯誤的。它會影響對象的構(gòu)建位(constructed bits)。 4.默認(rèn)構(gòu)造函數(shù)(default constructor )的參數(shù)可以使沒有,也可以使默認(rèn)的參數(shù)。如: class Fred { public: Fred(); // Default constructor: can be called with no args ... }; 或 class Fred { public: Fred(int i=3, int j=5); // Default constructor: can be called with no args ... }; 5.建立對象數(shù)組時,哪個構(gòu)造函數(shù)將被調(diào)用: 如果沒有默認(rèn)構(gòu)造函數(shù),那么創(chuàng)建對象數(shù)組將會出錯。如: class Fred { public: Fred(int i, int j); ← assume there is no default constructor ... }; int main() { Fred a[10]; ← ERROR: Fred doesn't have a default constructor Fred* p = new Fred[10]; ← ERROR: Fred doesn't have a default constructor ... } 如果用std::vector<Fred> ,則可以不用默認(rèn)構(gòu)造函數(shù)。如: #include <vector> int main() { std::vector<Fred> a(10, Fred(5,7)); ← the 10 Fred objects in std::vector a will be initialized with Fred(5,7) ... } 也可以現(xiàn)實初始化數(shù)組:也可以用placement new來手工初始化數(shù)組元素 class Fred { public: Fred(int i, int j); ← assume there is no default constructor ... }; int main() { Fred a[10] = { Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), // The 10 Fred objects are Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7) // initialized using Fred(5,7) }; ... } 一般的我們用vector來替代數(shù)組。 6.構(gòu)造函數(shù)中如何使用初始化列表(initialization lists)和賦值(assignment) 在構(gòu)造中使用初始化列表比賦值更有效率,后者比前者多了一個臨時變量,多了這個臨時變量的創(chuàng)建和銷毀的開銷。但是在內(nèi)置數(shù)據(jù)類型(int,float等)時,二者差別不大。 另一種情況是在構(gòu)造中的成員對象會被以默認(rèn)構(gòu)造函數(shù)完整的構(gòu)造,會分配一些缺省狀態(tài)下的內(nèi)存或是文件,這樣如果在構(gòu)造中如果使用表達(dá)式或復(fù)制失敗,是沒辦法來釋放資源或關(guān)閉文件的。 在下面情況下不易使用初始化列表:類有兩個構(gòu)造函數(shù)并且需要初始化這個數(shù)據(jù)成員按照不同的順序,或是有兩個數(shù)據(jù)成員自引用,或數(shù)據(jù)成員需要引用this對象,或者拋出一個異常之前要初始化這個this成員等。 7.構(gòu)造函數(shù)可以使用this指針嗎?可以,但是小心使用,甚至于在初始化列表中使用它。 可以使用的情況:構(gòu)造函數(shù)的函數(shù)體(或構(gòu)造函數(shù)所調(diào)用的函數(shù))能可靠地訪問基類中聲明的數(shù)據(jù)成員和/或構(gòu)造函數(shù)所屬類里聲明的數(shù)據(jù)成員。這是因為所有這些數(shù)據(jù)成員被保證在構(gòu)造函數(shù)函數(shù)體開始執(zhí)行時已經(jīng)被完整的建立。 構(gòu)造函數(shù)的函數(shù)體(或構(gòu)造函數(shù)所調(diào)用的函數(shù))不能向下調(diào)用被派生類重定義的虛函數(shù)。無論你如何調(diào)用虛成員函數(shù):顯式使用this指針(如,this->method()),隱式的使用this指針(如,method()),或甚至在this對象上調(diào)用其他函數(shù)來調(diào)用該虛成員函數(shù),原因:在基類的構(gòu)造函數(shù)執(zhí)行期間,派生類對象還未產(chǎn)生。 下面的情況有時是可行的:如果傳遞 this 對象的任何一個數(shù)據(jù)成員給另一個數(shù)據(jù)成員的初始化程序,你必須確保該數(shù)據(jù)成員已經(jīng)被初始化。他的優(yōu)點是不依賴編譯器,但是你必須知道一些語言規(guī)則(例如,基類子對象首先被初始化(如果有多重和/或虛繼承,則查詢這個次序!),然后類中定義的數(shù)據(jù)成員根據(jù)在類中聲明的次序被初始化),如果不知道就不要使用這個this指針。 8.命名的構(gòu)造函數(shù)法(Named Constructor Idiom): 作用就就是區(qū)分多個構(gòu)造函數(shù)。 結(jié)構(gòu):把構(gòu)造放到private或protected處,提供一個返回對象的public static 方法。每種不同的構(gòu)造對象的方法都有一個這樣的靜態(tài)方法。例子: class Point { public: Point(float x, float y); // Rectangular coordinates Point(float r, float a); // Polar coordinates (radius and angle) // ERROR: Overload is Ambiguous: Point::Point(float,float) }; int main() { Point p = Point(5.7, 1.2); // Ambiguous: Which coordinate system? ... } 解決方法就是使用Named Constructor Idiom #include <cmath> // To get sin() and cos() class Point { public: static Point rectangular(float x, float y); // Rectangular coord's static Point polar(float radius, float angle); // Polar coordinates // These static methods are the so-called "named constructors" ... private: Point(float x, float y); // Rectangular coordinates float x_, y_; }; inline Point::Point(float x, float y) : x_(x), y_(y) { } inline Point Point::rectangular(float x, float y) { return Point(x, y); } inline Point Point::polar(float radius, float angle) { return Point(radius*cos(angle), radius*sin(angle)); }
int main() { Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular Point p2 = Point::polar(5.7, 1.2); // Obviously polar ... } 如果Point有派生類,構(gòu)造就放在protected中。
|