zoukankan      html  css  js  c++  java
  • C++ 之 常量成员函数

      常量成员函数 (const member function), 可读取类中的数据成员,但不能修改

    1  声明

    1.1  const 关键字  

      参数列表后,加 const 关键字,声明为常量成员函数,表明其不被允许修改类的数据成员

      下面的类,以年、月、日的形式来表示日期 (注意:年月日的声明顺序)

    class Date {
    public:
        int GetYear() const { return y_; }int GetMonth() const { return m_; }
        int GetDay() const { return d_; }
        void AddYear(int n); // add n years
    private:
        int y_, m_, d_;  
    };

      1) 如果常量成员函数,企图修改类的数据成员,则编译器会报错

    // error : attempt to change member value in const function
    int Date::GetYear() const
    {
        return ++y_; 
    }

      2) 如果在类外面,“定义” 常量成员函数 ( “定义” = 实现,即 implementation),则 const 关键字不可省略

    // error : const missing in member function type
    int Date::GetYear() 
    {
        return y_;
    }

    1.2  C++ 陷阱

      类中成员变量的声明顺序,决定了成员变量的初始化顺序。假设 Date 类中的构造函数为:

    public:
        Date() : y_(2016), m_(9), d_(22) {}

      此时,类中的成员函数,在类中的声明顺序 = 构造函数初始化列表顺序,故 y_, m_, d_ 都能被顺利的初始化为对应的值。

      而当成员变量,在类中的声明顺序 ≠ 构造函数初始化列表顺序 时,

    public:
        Date() : y_(2016), d_(22), m_(d_-13) {}

      根据成员变量的声明顺序,y_ 首先被初始化为 2016,然后再初始化 m_,但由于 d_ 并未被初始化,所以 m_ 的值是随机的,最后初始化 d_ 为 22

      这是因为,类的成员变量在初始化时,其初始化的顺序只与声明顺序有关,而与在初始化列表中的顺序无关。

    2  调用

      一个常量成员函数,可以被 const 和 non-const 类对象调用; 而非常量成员函数,例如 AddYear(),则只能被 non-const 型类对象调用。

    void  Date::AddYear(int n)
    {
        y_ += n;  
    }

      调用函数如下:

    void f(Date& d, const Date& cd)
    {
        int i = d.GetYear();    // OK
        d.AddYear(1);        // OK
    int j = cd.GetYear(); // OK cd.AddYear(1); // error }

      此时,const 修饰函数形参,是 “接口” 的常用指定形式, 这样 数据 可以传递给 函数 而 本身不被修改

      C++ 中的类型转换 const_cast,可以移除对象的 const 属性,具体使用为: const_cast<T>(expression)

      则上例中,要使 const 型类对象,调用类的 non-const 成员函数,可修改代码如下:

    void f(Date& d, const Date& cd)
    {
        int j = cd.GetYear();    // OK
        const_cast<Date&>(cd).AddYear(1); 
    }

      这种做法虽然是可以的,但它破坏了使用 const 来指定 “接口“ 的本意,并不推荐。


    3  解释

      this 指针 默认是指向 non-const 型类对象的 const 型,因此,不能将 this 指针和 const 型类对象绑定,即 const 类对象无法调用类的成员函数

    // 默认的 this 指针,指向 non-const 类对象
    Date * const this;

       在成员函数声明的参数列表后加 const 后缀,表明其 this 指针指向 const 型类对象,如此, const 型类对象便可以调用常量成员函数了

    // 常量成员函数中的 this 指针,指向 const 类对象
    const Date * const this;

      

    小结:

    1) 类成员函数声明中的 const 后缀,表明其 this 指针指向 const 型类对象,因此该 const 类对象,可以调用常量成员函数 (const member function)

    2) 一个成员函数,如果对数据成员只涉及读操作,而不进行修改操作,则尽可能声明为常量成员函数

    参考资料:

     <C++ Programming Language_4th> ch 16.2.9.1

     <C++ Primer_5th> ch 7.1.2

     <Effective C++_3rd> Item 3, item 27

     <More Effective C++> Item 2

     <剑指 offer> 第 7 章

  • 相关阅读:
    uva 10369 Arctic Network
    uvalive 5834 Genghis Khan The Conqueror
    uvalive 4848 Tour Belt
    uvalive 4960 Sensor Network
    codeforces 798c Mike And Gcd Problem
    codeforces 796c Bank Hacking
    codeforces 768c Jon Snow And His Favourite Number
    hdu 1114 Piggy-Bank
    poj 1276 Cash Machine
    bzoj 2423 最长公共子序列
  • 原文地址:https://www.cnblogs.com/xinxue/p/5405362.html
Copyright © 2011-2022 走看看