构造函数
创建一个类类型的对象时,编译器会自动使用一个构造函数来初始化该对象,构造函数是一个特殊的、与类同名的成员函数,用于给每个数据成员设置适当的初始值。
构造函数通常使用一个构造函数初始化列表,来初始化对象的数据成员:
Sales_item(): units_sold(0), revenue(0.0) {}
构造函数初始化列表由成员名和带括号的初始值组成,跟在构造函数的形参表之后,并以冒号开头。
构造函数不能声明为const,创建类类型的const对象时,运行一个普通构造函数来初始化该对象,构造函数的工作是初始化对象,不管对象是否为const,都用一个构造函数来初始化该对象。
用于初始化一个对象的实参类型决定使用哪个构造函数。
构造函数初始化式
Sales_item::Sales_item(const string &book):
isbn(book), nuits_sold(0), revenue(0.0) {}
构造函数可以定义在类的内部或外部,初始化式只在构造函数定义中而不是声明中指定。省略初始化列表并在构造函数的函数体内对数据成员赋值是合法的。构造函数分俩阶段执行:初始化阶段和计算阶段。计算阶段由构造函数函数体中的所有语句组成。
没有默认构造函数的类类型成员,以及const或引用类型成员,不管哪种类型,必须用初始化列表进行初始化。
X(int val): i(val), j(val) {}
初始化式可以是任意表达式:
Sales_item(const std::string &book, int cnt, double price):
isbn(book), units_sold(cnt), revenue(cnt*price) {}
类类型的数据成员的初始化式:
Sales_item(): isbn(10,'9'), units_sold(0), revenue(0.0) {}
使用string构造函数,接受一个计数值和一个字符,并生成一个string,来保存重复指定次数的字符。
默认构造函数
只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数。
合成的默认构造函数使用与变量初始化相同的规则来初始化成员。每个构造函数应该为每个内置或复合类型的成员提供初始化式。没有初始化内置或复合类型成员的构造函数,将使那些成员处于未定义状态,除了作为赋值的目标外,以任何方式使用一个未定义的成员都是错的。
使用默认构造函数定义一个对象的正确方式是:
Sales_item myobj;
Sales_item myobj=Sales_item();
对于第二行语句,创建并初始化一个Sales_item对象,然后用它来按值初始化myobj。编译器通过运行Sales_tem的默认构造函数来按值初始化一个Sales_item。
抑制由构造函数定义的隐式转换
可以将构造函数声明为explicit来防止在需要隐式转换的上下文中使用构造函数:
class Sales_item{
public:
explicit Sales_item(const std::string &book=" "):
isbn(book),units_sold(0), revenue(0.0) {}
explicit Sales_item(std::istream &is);
};
explicit关键字只能用于类内部的构造函数声明上。在类定义体外部所做的定义上不再重复它。
友元
友元机制允许一个类将对其非公有成员的访问权授予指定的函数或类。友元的声明以关键字friend开始,只能出现在类定义的内部。友元可以是普通的非成员函数,或其他类的成员函数,或整个类,将一个类设为友元,友元类的所有成员函数都可以访问授予友元关系的那个类的非公有成员。
当我们将成员函数声明为友元时,函数名必须用该函数所属的类名字加以限定。
Static类成员
类可以定义类静态成员,而不是定义一个可普遍访问的全局对象。非static数据成员存在于类类型的每个对象中,不像普通的数据成员,static数据成员独立于该类的任意对象而存在,每个static数据成员是与类关联的对象,并不与该类的对象相关联。正如类可以定义共享的static数据成员一样,类也可以定义static成员函数,static成员函数没有this形参,它可以直接访问所属类的static成员,但不能直接使用非static成员。
class Account{
public:
void aaplyint() {amount+=amount*interestRate}
static double rate() {return interestRate;}
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
};
Account ac1;
Account *ac2=&ac1;
double rate;
rate=ac1.rate();
rate=ac2->rate();
rate=Account::rate();
static成员是类的组成部分但不是任何对象的组成部分,因此,static成员函数没有this指针。通过使用非static成员显式或隐式地引用this是一个编译时错误。static成员函数不能被声明为const,也不能被声明为虚函数。
static数据成员必须在类定义体的外部定义(正好一次)不像普通数据成员,static成员不是通过类构造函数进行初始化,而应该在定义时进行初始化。
double Account:: interestRate=initRate();
尽管initRate是私有的,仍然可以使用该函数来初始化interestRate,像任意的其他成员定义一样,interestRate的定义是在类的作用域中,因此可以访问该类的私有成员。
普通成员都是给定类的每个对象的组成部分,static成员独立于任何对象而存在,不是类类型对象的组成部分,static数据成员的类型可以是该成员所属的类类型,非static成员被限定声明为其自身类对象的指针或引用:
class Bar{
public:
....
private:
static Bar mem1;
Bar *mem2;
};
Static数据成员可用作默认实参:
class Screen{
public:
Screen& clear(char=bkground);
private:
static const char bkground='#';
};
非static数据成员不能用作默认实参,因为其值不能独立于所属的对象而使用,使用非static数据成员作默认实参,将无法提供对象以获取该成员的值,因而是错的。