1.功能:建立(build objects)對象,將一連串的隨意的記憶體位變對象,也分配資源(memory, files, semaphores, sockets等),"ctor" 是建構函式(constructor)典型的縮寫。
2.假定List是個類名,List x和 List x()的區別:前者聲明了一個List對象,後者則是一個函數,返回List類型。
3.能否在一個建構函式中調用另一個建構函式?答案是否定的。
假設類Fro有兩個建構函式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,
...
}
也可以組合這兩個建構函式,通過預設參數
class Foo {
public:
Foo(char x, int y=0); // this line combines the two constructors
...
};
如果沒有預設參數可用,那麼我可以共用公用代碼在私人的Init函數中,如:
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)中,有些人認為可以new(this) Foo(x, int(x)+7)在Foo::Foo(char)中,這是絕對錯誤的。它會影響對象的構建位(constructed bits)。
4.預設建構函式(default constructor )的參數可以使沒有,也可以使預設的參數。如:
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.建立對象數組時,哪個建構函式將被調用:
如果沒有預設建構函式,那麼建立對象數組將會出錯。如:
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> ,則可以不用預設建構函式。如:
#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)
...
}
也可以現實初始化數組:也可以用placement new來手工初始化數組元素
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來替代數組。
6.建構函式中如何使用初始化列表(initialization lists)和賦值(assignment)
在構造中使用初始化列表比賦值更有效率,後者比前者多了一個臨時變數,多了這個臨時變數的建立和銷毀的開銷。但是在內建資料類型(int,float等)時,二者差別不大。
另一種情況是在構造中的成員對象會被以預設建構函式完整的構造,會分配一些預設狀態下的記憶體或是檔案,這樣如果在構造中如果使用運算式或複製失敗,是沒辦法來釋放資源或關閉檔案的。
在下面情況下不易使用初始化列表:類有兩個建構函式並且需要初始化這個資料成員按照不同的順序,或是有兩個資料成員自引用,或資料成員需要引用this對象,或者拋出一個異常之前要初始化這個this成員等。
7.建構函式可以使用this指標嗎?可以,但是小心使用,甚至於在初始化列表中使用它。
可以使用的情況:建構函式的函數體(或建構函式所調用的函數)能可靠地訪問基類中聲明的資料成員和/或建構函式所屬類裡聲明的資料成員。這是因為所有這些資料成員被保證在建構函式函數體開始執行時已經被完整的建立。
建構函式的函數體(或建構函式所調用的函數)不能向下調用被衍生類別重定義的虛函數。無論你如何調用虛成員函數:顯式使用this指標(如,this->method()),隱式的使用this指標(如,method()),或甚至在this對象上調用其他函數來調用該虛成員函數,原因:在基類的建構函式執行期間,衍生類別對象還未產生。
下面的情況有時是可行的:如果傳遞 this 對象的任何一個資料成員給另一個資料成員的初始化程式,你必須確保該資料成員已經被初始化。他的優點是不依賴編譯器,但是你必須知道一些語言規則(例如,基類子物件首先被初始化(如果有多重和/或虛繼承,則查詢這個次序!),然後類中定義的資料成員根據在類中聲明的次序被初始化),如果不知道就不要使用這個this指標。
8.命名的建構函式法(Named Constructor Idiom):
作用就就是區分多個建構函式。
結構:把構造放到private或protected處,提供一個返回對象的public static 方法。每種不同的構造對象的方法都有一個這樣的靜態方法。例子:
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有衍生類別,構造就放在protected中。