《C++ Primer》读书笔记第七章-3-构造函数再探 And 类的静态成员

笔记会持续更新,有错误的地方欢迎指正,谢谢!

构造函数再探

构造函数初始值列表

我们初始化 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){}
}

这是这个类的默认构造函数,它用到了默认实参,这么写的好处是:

  1. 不传参数时,也能调用(就相当于默认构造函数,它就用空字符串s去初始化bookNo。)
  2. 传参数时,就按照传的来呗。一石二鸟呗,实用哈。

委托构造函数

就是调用 普通的构造函数 帮忙初始化。

默认构造函数的作用

记住一条好习惯:如果定义了其他的构造函数,最好也提供一个默认构造函数,下面来看一个没有默认构造函数的经典错误:

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是不完全类型~

};

因为静态成员一般在外面定义初始化,所以,在类内可以是不完全类型,便可胡作非为。

总结:静态成员的优势:

  1. 类内可包含自身类型的静态数据成员,但普通成员只能是指针或引用;
  2. 静态成员可以作为默认实参,非静态数据成员的值属于对象的一部分,不能作为默认实参。因为静态成员与类绑定,是类的所有对象来共享的。所以类的对象不同时就用不了咯~(此优势未举例,自己领会哈~)

本章小结:

  1. 类允许我们为自己的应用特制类型
  2. 类有两项基本能力:
    数据抽象,就是定义数据成员和函数成员
    封装,保护类的成员不被随意访问(private,友元等)
  3. 构造函数可以控制初始化对象的方式
  4. 静态成员与类绑定,存在于对象之外,是所有对象来共享的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值