c++ primer 5th 笔记:第七章

第七章:类

  笔记

    1. 定义在类内部的函数是隐式的inline函数。

    2. 使用const的成员函数被称作常量成员函数(const member function)。

    3. 首先编译成员的声明,然后才轮到成员函数体。因此,成员函数体可以随意使用类中的其他成员而无须在意这些成员出现的次序。

    4. IO类属于不能被拷贝的类型,因此只能通过引用来传递它们。

    5. 每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程。这些函数叫做构造函数

    6. 默认构造函数无须任何实参。如果我们的类没有显示定义任何构造函数,那么编译器就会为我们隐式地定义一个默认函数,被称作合成的默认构造函数。合成的默认构造函数只适合非常简单的类。

    7. 在c++11新标准中,如果我们需要合成默认构造函数的行为,那么可以通过在参数列表后面写上=default来要求编译器生成构造函数。如果=default在类的内部,则默认构造函数是内联的;如果它在类的外部,则该成员默认情况下不是内联的。

    8. 类还需要控制拷贝、赋值和销毁对象时发生的行为。如果我们不主动定义这些操作,则编译器将替我们合成它们。

    9. 类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友员(friend)

    10. 一个可变数据成员(mutable data member)永远不会是const,即是它是const对象的成员。

    11. 仅声明类而暂时不定义它,这种声明被称作前向声明(forward declaraion),在它声明之后定义之前是一个不完全类型

    12. 当一个名字第一次出现在一个友元声明中时,我们隐式地假定该名字在当前作用域中时可见的(即在声明前就使用这个名字)。

    13. 随着构造函数一开始执行,初始化就完成了。因此,我们初始化const或者引用类型的数据成员唯一的机会就是通过构造函数初始值。 成员的初始化顺序与他们在类定义中的出现顺序一致。

    14. 如果一个构造函数为所有参数都提供了默认参数,则它实际上也定义了默认构造函数。

    15. c++新标准扩展了构造函数初始值的的功能,使得我们可以定义所谓的委托构造函数

    class Sales_data
    {
    pulic:
        // 非委托构造函数使用对应的实参初始化成员
        Sales_data(std::string s, unsigned cnt, double price):
                            bookNo(s), units_sold(cnt), revenue(cnt*price)  {  }
        // 其余构造函数全部委托给另一个构造函数
        Sales_data() : Sales_data("", 0, 0)   { }
        Sales_data(std::string s) : Sales_data(s, 0, 0)    { }
        Sales_data(std::istream &is) : Sales_data()
                                      {  read(is, *this);   }
        // 其他成员与之前的版本一样
    };
        // 执行顺序:当这些委托的构造函数执行完后,接着执行istream&构造函数体的内容。
        // 当一个构造函数委托给另一个构造函数时,受委托的构函数的初始值列表和函数体被
        // 依次执行。

    16. 我们通过在成员的声明之前加上关键字static使得其与类关联在一起。静态成员函数不与任何对象绑定在一起,它们不包含this指针。我们可以使用作用域运算符符直接访问静态成员(Account::rate()),也可以使用类的对象来访问静态成员。

    17. 我们不能在类的内部初始化静态成员。相反,必须在类的外部定义和初始化每个静态成员

  重点知识点总结 

    聚合类和字面值常量类(待补充)。

    隐式的类类型转换

      C++语言在内置类型之间定义了几种自动转换规则。同样,我们也能为类定义隐式转换规则。如果构造函数只接受一个实参,则它实际上定义了 转换为此类类型的隐式转换机制,有时我们把这种构造函数称作为转换构造函数(converting constructor)。

      string null_book = "9-999-99999-9";
      // 构造一个临时的Sales_data对象
      // 该对象的units_sold和revenue等于0,bookNo等于null_book
      item.combine(null_book); 
      // 因为combine的参数是一个常量引用,所以我们可以给该参数传递一个临时量

      只允许一步类类型转换。

      // 错误:需要用户定义的两种转换
      // (1) 把"9-999-99999-9"转换成string
      // (2) 再把这个(临时的)string转换成Sales_data
      item.combine("9-999-99999-9");   // 错误

      抑制构造函数定义的隐式转换。我们可以通过将构造函数声明为explicit加以阻止。而且,explicit关键字只允许出现在类内的构造函数声明处。

      class Sales_data
      {
       public:
              Sales_data() = default;
              Sales_data(const std::string &s, unsigned n, double p) :
                                  bookNo(s), units_sold(n), revenue(p*n)  {   }
              explicit Sales_data(const std::string &s) : bookNo(s)    {   }
              explicit Sales_data(std::istream&);
      };

      item.combine(null_book);  // 错误:string构造函数是explicit的
      item.combine(cin);     // 错误:istream构造函数是explicit的

      显式强制进行转换

      item.combine(static_cast<Sales_data>(cin)); 
        // 正确:static_cast可以使用explicit的构造函数

 

  术语 

    数据抽象(data abstraction)、封装(encapsulation)、抽象数据类型(abstract data type)、成员函数(member function)、访问说明符(access specifiers)、构造函数初始值列表(constructor initializer list)、显示构造函数(explicit constructor)、友元(friend)、合成默认构造函数(synthesized default constructor)。

    构造函数初始值列表:说明一个类的数据成员的初始值,在构造函数体执行之前首先用初始值列表中的值初始化数据成员。未经初始化的成员将被默认初始化。

    显式构造函数:可以使用一个单独的实参调用但是不能用于隐式转换的构造函数。

                                                2016-10-30 15:37:31

posted @ 2016-10-30 15:38  西伯利亚狼zz  阅读(379)  评论(0编辑  收藏  举报