笔记会持续更新,有错误的地方欢迎指正,谢谢!
构造函数再探
构造函数初始值列表
我们初始化 const数据 或 引用类型的数据 的唯一机会就是通过构造函数初始值,于是我们可以这么写:
class ConstRef
{
public:
ConstRef(int value) : i(value), ci(value), ri(i){}
private:
int i;
const int ci;
int &ri;
};
总结:如果成员是const、引用或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值。
另外,成员的初始化顺序与它们在类定义中的出现顺序一致,而与初始化列表无关,这句话经常考!
例子:
class X
{
int i;
int j;
public:
X(int val) : j(val), i(j){}//i先被初始化。
};
这样是错的。因为怎么能用未初始化的j去初始化i呢?
最好的方式是用构造函数传进来的参数去初始化成员,这样我们就不用考虑初始化顺序了:X(int val) : i(val), j(val){}
默认实参和构造函数:
默认构造函数是没有参数的,但我们可以这么干:
class Sales_data
{
public:
Sales_data(string s = "") : bookNo(s){}
}
这是这个类的默认构造函数,它用到了默认实参,这么写的好处是:
- 不传参数时,也能调用(就相当于默认构造函数,它就用空字符串s去初始化bookNo。)
- 传参数时,就按照传的来呗。一石二鸟呗,实用哈。
委托构造函数
就是调用 普通的构造函数 帮忙初始化。
默认构造函数的作用
记住一条好习惯:如果定义了其他的构造函数,最好也提供一个默认构造函数,下面来看一个没有默认构造函数的经典错误:
class NoDefault
{
public:
NoDefault(const string &);//定义了构造函数,但没有定义默认构造函数。
};
struct B
{
B(){}
NoDefault b;
//b作为类类型成员,构造函数没有初始化它,于是它会调用默认构造函数初始化,结果该死的NoDefault没有默认构造函数。
};
默认构造对象:使用默认构造函数定义对象的格式为类名+对象名,后面没有空括号,否则就变成了定义函数。
聚合类
此类不常用~
什么样的类是聚合类呢?满足下面四个条件:
1.所有成员都是public;
2.没有定义任何构造函数;
3.没有类内初始值;
4.没有基类,也没有virtual函数;
5.使用花括号初始化;
6.花括号内的初始值顺序与声明顺序一致。
举例:
struct Data
{
int val;
string s;
};
Data a = {0, "temp"}; //实例化,一定要按类内定义的顺序来初始化。
字面值常量类
此类不常用~
不讲了。
类的静态成员
有时候,类需要它的一些成员与类本身直接相关。
例如:银行账户类和利率成员,我们希望利率成员与类直接关联,而不是和银行卡对象关联。也就是,一旦利率成员变化,我们希望所有的银行卡对象都能使用新值。
声明静态成员
static double interestRate;
使用类的静态成员
使用类作用域运算符::直接访问:
double r;
r = Account::rate();
同样可用对象去访问静态成员
Account c1;
Account *ac2 = &ac1;
r = ac1.rate();
r = ac2->rate();
以上是在类外访问,如果在类内呢?直接访问呗。
定义静态成员
类的静态成员应该在类内声明,类外定义。类成员函数的声明只能放在类内,在类外部定义静态成员时,不能再用static关键字,该关键字只能出现在类内部的声明语句。
我们来定义一个在类内已经声明的static成员:
double Account::interestRate = initRate();
静态数据成员一旦被定义,就一直存在于程序的整个生命周期中。
静态成员的类内初始化
刚刚说过,类的静态成员应该在类外定义,于是C++又来破坏自己定的规矩了。什么狗屁东西,不学了!食之无味弃之可惜。
静态成员能用于某些场景,而普通成员不能
由于静态成员独立于任何对象,所以静态数据成员可以是不完全类型。
不完全类型的特殊情况:静态数据成员可以是它所属的类类型。
而非静态数据成员则受限制,只能声明成它所属类的指针或引用,才可如此用。如下方的Bar *m2;
class Bar
{
private:
static Bar m1; //这个牛,因为m1是不完全类型的特殊情况。
Bar *m2;//这个也牛,所属类的非静态数据成员的指针 也是不完全类型。
static int &m2; //这个更牛,未初始化的引用。因为m2是不完全类型~
};
因为静态成员一般在外面定义初始化,所以,在类内可以是不完全类型,便可胡作非为。
总结:静态成员的优势:
- 类内可包含自身类型的静态数据成员,但普通成员只能是指针或引用;
- 静态成员可以作为默认实参,非静态数据成员的值属于对象的一部分,不能作为默认实参。因为静态成员与类绑定,是类的所有对象来共享的。所以类的对象不同时就用不了咯~(此优势未举例,自己领会哈~)
本章小结:
- 类允许我们为自己的应用特制类型
- 类有两项基本能力:
数据抽象,就是定义数据成员和函数成员
封装,保护类的成员不被随意访问(private,友元等) - 构造函数可以控制初始化对象的方式
- 静态成员与类绑定,存在于对象之外,是所有对象来共享的。