构造函数的名字和类的名字相同,没有返回类型,在类的public域定义或声明。
使用构造函数的三类方式:
1)显示调用:e.g. Stock food = Stock("World Cabbage", 250, 1.25);
2)隐式调用:e.g. Stock garment("Furry Mason", 50, 2.5);
3)new:e.g. Stock *pstock = new Stock("Electric", 18, 19.0); //这种情况下,创建了一个没有名字的Stock对象,将这个对象的地址赋给pstock,通过指针pstock使用这个对象。
默认构造函数:
默认构造函数没有形参表。如果用户没有定义任何构造函数,编译器会自动生成一个默认构造函数。但编译器自动生成的默认构造函数不做任何事,e.g. Stock::Stock() {}。这样带来的结果就是, e.g. Stock st; st中的成员都未初始化。
如果用户定义了任何构造函数,那编译器就不会提供默认构造函数,用户必须自己定义默认构造函数。如果用户定义了带形参的构造函数,但没有定义默认构造函数,那如下的情况将会报错:
Stock stock1; // Error, no default constructor
定义自己的默认构造函数有两种方式:
1)隐式初始化:在默认构造函数体内对数据成员赋值。
e.g. Stock::Stock()
{ //在执行函数体之前,其实成员变量已经初始化过了,即company="", shares和share_value值未知
company = "no name";
shares = 0;
share_value = 0.0;
}
2)显式初始化:在默认构造函数初始化列表中对数据成员初始化。
e.g. Stock::Stock: company(""),shares(0),share_value(0.0) {}
初始化列表只在构造函数的定义中而不是声明中指定。
一般情况下,这两种方式没有差别,但2)效率更高,建议使用2)。
但有些情况下,只能使用2)来初始化数据成员。当类的成员中有const或引用类型成员以及没有默认构造函数的类类型成员时,必须使用2)。因为对于const成员或引用类型成员,只能初始化,不能对他们赋值;对于没有默认构造函数的类类型成员,若采用1),则给它赋值之前其实它已经被创建,但因没有默认构造函数,所以会创建失败,因此也只能用2)初始化。
在使用2)时,成员被初始化的次序就是定义成员的次序,与初始化列表中的次序无关。
使用默认构造函数的几种情况:
1) Stock first;//隐式调用默认构造函数
2) Stock first = Stock();//显示调用默认构造函数
3) Stock *pst = new Stock;//隐式调用默认构造函数
4) Stock *pst1 = new Stock();//显示调用默认构造函数
Stock second(); // 错误,这是声明一个返回类型为Stock的函数,不是声明对象。
注意:内置或复合类型的成员的初始值依赖于对象的作用域:在局部作用域中这些成员不被初始化,而在全局作用域中它们被初始化。
e.g.
class base
{
private:
int a;
double b;
};
base A;//a=0,b=0.0
main()
{}
int a;
double b;
};
base A;//a=0,b=0.0
main()
{}
class base { private: int a; double b; }; main() { base B; //如果没有default constructor,则a,b均未初始化,没有初始值 }
int a; double b; }; main() { base B; //如果没有default constructor,则a,b均未初始化,没有初始值 }