7.5构造函数再探
构造函数初始化列表
const和引用必须进行初始化,而不能在构造函数中赋值。
class ConstRef {
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};
ConstRef::ConstRef(int ii)
{
i = ii;
ci = ii; //错误:不能给const赋值
ri = i; //错误:ri没被初始化
}
//正确的做法
ConstRef::ConstRef(int ii):i(ii),ci(ii),ri(i){ }
养成使用构造函数初始值列表的习惯。
成员初始化顺序
成员初始化的顺序和它们在类中定义中出现的顺序一致。
最好令构造函数的初始值列表顺序与成员声明的顺序保持一致,尽量避免使用某些成员初始化其他成员,最好直接使用构造函数的参数。
class X{
int i;
int j;
public:
x(int val): j(val), i(j){ }
}
默认实参
如果一个构造函数为所有参数都提供了默认实参,则它实际上也定义了默认的构造函数。
class Sales {
Sales(std::string s = ""): bookNo(s){ }
};
委托构造函数
C++11标准
委托构造函数使用所属类的其他构造函数执行自己的初始化过程。
当一个构造函数委托另一个构造函数时,受委托的构造函数的初始值列表和函数体依次被执行,然后才执行委托者的函数体。
class Sales {
public:
Sales(std::string, unsigned cnt, double price):
bookNo(s), units_sold(cnt), revenue(cnt*price) { }
Sales():Sales("", 0, 0){ } //使用了委托构造函数
Sales(std::string s):Sales(s, 0, 0){ }
private:
std::string bookNo;
unsigned units_sold;
double revenue;
};
隐式的类类型转换
如果一个构造函数只接受一个实参,则他实际上定义了转换为此类类型的隐式转换机制。
string book = "ssss";
item.combine(book); //combine的参数是Sales类型,自动调用了Sales只接受string类型的构造函数,创建了一个临时的Sales对象。
但是注意:只接受一步类型转换。
可以把构造函数声明为explicit来阻止隐式的类型转换
class Sales {
public:
Sales(std::string, unsigned cnt, double price):
bookNo(s), units_sold(cnt), revenue(cnt*price) { }
explicit Sales():Sales("", 0, 0){ } //使用了委托构造函数
explicit Sales(std::string s):Sales(s, 0, 0){ }
private:
std::string bookNo;
unsigned units_sold;
double revenue;
};
string book = "ssss";
item.combine(book); //报错,构造函数是explicit
直接初始化:
null_book = "AAA"
Sales item1(null_book)
拷贝初始化:
Sales item1 = null_book;
explicit构造函数只能用于直接初始化。
聚合类
当一个类满足以下条件时,是一个聚合类:
- 所有的成员都是public
- 没有定义任何的构造函数
- 没有类内初始值
- 没有基类,没有virtual函数
比如:
struct Data{
int ival;
string s;
}
我们可以提供一个花括号括起来的成员初始化列表来初始化聚合类的数据成员。
Data vall = { 0, "Anna"};
初始值顺序和声明顺序必须一致。
如果初始值列表的元素个数少于类的成员数量,那么靠后的成员使用默认值。
显示的初始化聚合类的对象的缺点:
- 添加或者删除一个成员之后,所有的初始化语句都要更新。
- 将正确的初始化对象的任务交给了用户,没有提供初始值。
7.6类的静态成员
有时候类需要一些成员和类本身直接相关。
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。
同样,静态成员函数体内,不包含this指针。静态成员函数不能被声明为const.
使用类的静态成员:
使用作用域直接访问静态成员。
使用类的对象,引用和指针访问。
class Account{
public:
static double rate(){ return interestRate;}
static void get();
private:
static double interestRate;
};
int main(){
double r;
r = Account::rate();
Account ac1;
Account *ac2 = &ac1;
r = ac1.rate();
r = ac2->rate();
}
void Account::get(double new) //类外部定义
{
interestRate = new;
}
定义静态函数:
在类的外部定义静态数据成员时,不能重复static关键字,该关键字只出现在类的内部
生命周期类似全局变量,一旦被定义,就一直存在于程序的整个生命周期中。
可以使用类的私有成员来定义静态成员变量。
作用场景:
我们可以使用静态成员作为默认实参。非静态数据成员不能作为默认实参。