• C++中const


    【const】

    0.普通const对象定义在栈空间中

    {
        int a = 10;
        const int b = 100;
        cout << &a << ' ' << &b;
    }

    Result:

     0x22abec 0x22abe8

    注:Code::Blocks + Cygwin测得。

    1.对变量类型加以限定,使之不能被修改;

    const int e1 = 100;

    e1 = 101; // error

    2.const对象必须被初始化;

    const int e2; // error

    3.const对象和non-const对象可以通过彼此进行赋值;const对象也可以通过表达式进行初始化;

    int get_size() { return 100; }
    
    int main()
    {
        int i = 10;
        const int a = i; // non-const to const
        const int b = a; // const to const
        int c = a; // const to non-const
        int d = i; // non-const to non-const
    
        int e = get_size();
    
        return 0;
    }

    4.默认情况下,const对象仅在文件内有效(From定义之后To文件末尾);

    5.要在多个文件内共享一个const对象,需要使用extern关键字;

    《C++ Primer》第五版的说法有一点问题,即“对于const变量不管是声明还是定义都添加extern关键字,这样只需定义一次就可以了”。

    经过测试:可以在定义时不添加extern关键字,即下面的代码是可行的:

    // file1.cpp
    const int a = 100;
    
    // file2.cpp
    extern const int a;

    但在声明和定义时都添加extern关键字应该是“最佳实践”,即在定义时就说明此const变量为整个工程可见。

    6.const引用

    6.1 不能通过const引用修改对象的值,无论其指向的对象是否为const对象;

    6.2 非const引用不能指向一个const对象;

    {
        int i = 10;
        const int a = i;
    
        int& b = i;
        int& c = a; // error, 6.2
        const int& d = i;
        d = 1000; // error, 6.1
        const int& e = a;
        e = 1000; // error, 6.1
    }

    6.3 将一个const引用绑定到另外一种类型上发生了什么:

    {
        double dval = 3.14;
    
        const double& rd = dval;
        const int& ri = dval;
    
        cout << &dval << ' ' << &rd << endl;
        cout << &dval << ' ' << &ri << endl;
    }
    
    Result:
    0x22abd8 0x22abd8 // ok
    0x22abd8 0x22abe4 // wrong!

    整形const引用的地址和dval的地址不一致。《C++ Primer》解释说,这是因为类型转换发生时,ri指向的是一个临时变量,并且,C++将这种行为归为非法。

    但却能run起来。

    7.指向和const

    7.1 指向const对象的指针(pointer to const):a.禁止指向非const对象的指针 指向 const对象;b.禁止将 指向const的指针 赋值给 指向非const的指针;

    7.2 不能更改指向const对象的指针的值;

    {
        const double cpi = 3.14;
        double *ppi = &cpi; // error, 7.1.a
        const double *cppi = &cpi;
    
        double pi = 3.14;
        double *ppi2 = &pi;
        *ppi2 = 1000.0;
        const double *cppi2 = &pi;
    ppi2 = cppi2; // error, 7.1.b
    *cppi2 = 100.0; // error, 7.2 }

    7.3 常量指针(const pointer):必须初始化、一旦完成初始化就不能更改、若所指对象非const,则可以修改其值;

    {
        int a = 100;
        int b = 1000;
    
        int *p1 = &a;
        *p1 = 200;
        p1 = &b;
    
        int* const cp2 = &b;
        *cp2 = 201; // ok
        cp2 = &b; // error, pointer is const
    
        int* const cp3; // error, uninitialized
    }

    8.顶层const,底层const

    顶层const:对象本身是否为常量,整数本身、对象本身、指针本身,即自己,不能改变自己;

    底层const:指针 所指对象是否为常量,不能改变指针 所指对象 的值;

    const int * const pi = &a; // 1.前一个const为底层const,后一个const为顶层const;2.从右往左阅读法;

    9.类与const

    9.1 const成员函数

    作用:修改隐式this指针的类型。添加const之后,this指针所指对象的普通数据成员(非static非mutable)不能被更改。

    类型转换实值:将 T* const this 更改为 const T* const this,此时,this指针所指对象可以是const对象。

    9.2 const对象,以及const对象的引用或指针都只能调用const成员函数;

    struct X {
        X(int x, int y) : ex(x), ey(y) {};
    
        void display1() { cout << ex << endl; }
        void display2() const { cout << ey << endl; }
    
        int ex;
        int ey;
    };
    
    int main()
    {
        X x(12, 23);
        x.display1();
        x.display2();
    
        const X cx(34, 45);
        cx.display1(); // error, display1为非const成员函数
        cx.display2();
    
        return 0;
    }

    9.3 若成员函数为const,则其声明和定义都必须添加const(与上面说的extern的用法不同);

    9.4 成员函数可以根据const属性进行重载;

    struct X {
        void display() {}
        void display() const {}
    };

    9.5 const成员变量:a.不能被修改;b.能进行类内初始化;c.若已类内初始化,则可以使用默认构造函数;d.可以在构造函数初始化列表中初始化;

     1 struct X {
     2     X() {}; // 默认构造函数
     3     X(int x, int y) : ex(x), ey(y) {};
     4 
     5     void display1() { cout << ex << endl; }
     6     void display2() const;
     7 
     8     const int ex = 99; // 类内初始化
     9     const int ey = 100; // 类内初始化
    10 };
    11 void X::display2() const { cout << ey << endl; }

    若未进行类内初始化,则默认构造函数不能通过编译,即当上面代码的8、9行没有赋值时,上面的默认构造函数不能通过编译,无论是否用到此默认构造函数;

    若未进行类内初始化,又需要使用默认构造函数,可以在默认构造函数的初始化列表中给const成员变量赋值:

    X() : ex(99), ey(100) {};

    其中的99、100可以更改为其它表达式:

    int out1 = 99;
    
    struct X {
        X() : ex(out1), ey(out1+1) {}
        ...
    };

    -------------------------------------------------------------------

    其它:

    1.用于声明引用的const都是底层const,即不存在顶层const

    const int a = 100;
    const int & const b = a; // error: 'const' qualifiers cannot be applied to 'const int&'

    2.引用可以赋值给引用

    int a = 10;

    int& b = a;

    int& c = b; // ok, b is a reference

    但const引用不能赋值给非const引用

    const int& c = a;

    int& d = c; // error

  • 相关阅读:
    LeetCode Trapping Rain Water
    [Elasticsearch] 部分匹配 (四)
    SPOJ VLATTICE Visible Lattice Points (莫比乌斯反演基础题)
    SICP 习题 (1.35)解题总结
    光流(optical flow)和openCV中实现
    LZMA C# SDK 结合 UPK 打包压缩 多目录 Unity3d实例
    tabhost实现android菜单切换
    12306火车票订票失败!您的身份信息未经核验,一般人是不能订票的,我订了,可是没成功。。。
    WebService学习之旅(四)Apache Axis2的安装
    WebService学习之旅(三)JAX-WS与Spring整合发布WebService
  • 原文地址:https://www.cnblogs.com/luo630/p/4187684.html
Copyright © 2020-2023  润新知