第7章 类

7.1 定义抽象类型
  • this指针

    调用成员函数时,实际上在替某个对象调用它,成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象

    //实际执行过程
    Sales_data::isbn(&total);
    //在total对象调用函数时,将对象的地址传入,初始化this指针
    //任何对类成员的直接访问都可以被看做this的隐式引用
    return book; //等价于 return this->book;	book为数据成员
    
  • 引入const成员函数

    string isbn() const {return bookNo};
    
    • this的类型是ClassType *const顶层const,不能让其指向const ClassType对象也就使得,不能在常量对象上调用普通的成员函数
    • 通过使用const修改this指针的类型为const ClassType *const,这样的函数成为常量成员函数
    • 常量对象,以及常量对象的引用和指针,只能调用常量成员函数
  • 构造函数

    • 构造函数不能声明为const,构造函数的结果就是隐式的返回一个对象,如果这个对象是const的,那它就不能访问非const的函数。
    • 构造函数在const对象的构造过程中可以向其写值。
    • 对于数据成员,若存在类内初始值,则使用其进行初始化,否则执行默认初始化
  • 一个普通的类必须定义自己的默认构造函数

    • 只有在未定义任何构造函数的情况下才会自动生成默认构造函数,一旦定义了自己的构造函数,则必须有默认构造函数
    • 合成的构造函数可能执行错误的操作(定义在块内的内置类型和复合类型的对象被默认初始化,其值将是未定义的)
    • 不能为某些类合成构造函数,类中包含其他类类型,并且该类型没有默认构造函数
    • 使用=default,在类内,使得默认构造函数是内联的
  • 初始值列表

    Sales_data(const string& s):bookNo(s){}
    //冒号后面即为初始值列表
    //不同成员之间使用逗号分隔
    //不在列表中的成员执行默认初始化
    

    没有在构造函数初始值列表中显示初始化成员,则该成员将在构造函数体之前执行默认初始化,然后再执行函数体的赋值操作

7.2 访问控制与封装
  • 友元

    • 令其他类或者函数成为它的友元

    • friend关键字开始的函数声明

    • 定义在类内部,友元函数必须指明其属于哪个类

      class A
      {
          public:
          	friend class C;
          private:
          	int data;
      }
      
      class C
      {
       public:
          void show(A a)
          {
              cout<<a.data<<endl;
          }
          
      }
      
    • 友元仅指定了访问权限,而非真正的声明

    • 若希望能调用某个友元函数,那么必须在友元声明外再对函数声明一次

    • 友元不具备传递性

  • 定义在类内部的成员函数是自动inline的

  • mutable

    可变数据成员,被mutable修饰的成员永远不会是const,即使是const对象的成员,也可以修改

  • 不完整类型

    可以定义指向该类型的指针或引用,也可以声明(但不能定义)以其为参数或者返回类型的函数,一个类的成员类型不能是该类自己

7.3 构造函数再探
  • 初始化顺序

    • 成员的初始化顺序与定义顺序一直,不受初始值列表顺序的影响。

    • 如果一个构造函数为所有参数都提供了默认实参,那么实际上也就定义了默认构造函数

  • 委托构造函数

    //使用所在类的其它构造函数执行自己的初始化过程
    //即把自己的一些职责委托给其他构造函数
    class Sales_data
    {
     public:
        Sales_data(string s,unsigned cnt,double price):
        	bookNo(s),units_sold(cnt),revenue(cnt*price){}
        Sales_data():Sales_data("",0,0){}		//委托构造函数
        Sales_data(string s):Sales_data(s,0,0){}	//委托构造函数
    }
    
  • 隐式的类类型转换(转换构造函数)

    Sales_data类中,接受string的构造函数和接收istream的构造函数分别定义了这种类型向Sales_data隐式转换的规则,即可用string 和istream作为Sales_data的替代

    string null_book="999";
    item.combine(null_book);
    //item是类的对象,combine定义的形参也是类类型,这里直接使用string 代替
    //即可以隐式转换
    //但是这种隐式转换编译器只能执行一不
    item.combine("999");	//错误
    
  • 抑制构造函数定义的隐式转换

    //使用explicit关键字
    explicit Sales_data(const string &s):bookNo(s){}
    
  • 聚合类

    • 所有成员都是public

    • 没有定义任何构造函数

    • 没有基类,没有虚函数

    • 可以使用一个花括号括起来的成员初始值列表,来初始化聚合类数据成员

      class A
      {
       public:
          string s;
          int i;
      }
      
      ...
      A a={"xxx",0};
      //若列表的大小小于数据成员,靠后的将被【值初始化】
      //其长度不能大于数据成员长度
      
  • 值初始化

    当对象被默认初始化或者值初始化时,自动执行默认构造函数

    • 数据初始化过程中,提供的初始值少于其大小时,执行值初始化
    • 不使用初始值定义一个局部静态变量时
    • 通过T()的形式显示地请求初始化时
7.4 类的静态成员
  • 静态成员与类的本身相关,而不是与类的对象保持关联
  • 类的静态成员存在于任何对象之外
  • 静态成员函数不与任何对象绑定,其不含this指针,同时静态成员函数不能声明为const
  • 虽然静态成员不属于类的对象,但是可以用类的对象、指针、引用来访问,成员函数可以不使用作用域运算符就可以直接访问静态成员
  • 静态数据成员不由构造函数初始化,并且一般不能再类的内部初始化静态数据成员,应该定义在任何函数之外
  • 静态数据成员可以是不完整类型,特别的,可以是所属的类类型
  • 可以使用静态成员作默认参数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值