1ms Faster
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)

Quincy Jet

We are.
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)
  • Lean in c++

    • Lean in C++
    • Phase_0:Glimpse

      • C++ Glimpse
      • type cast
      • typedef
      • class vs. typename
      • const
        • const修饰一般变量
        • const修饰指针
        • const修饰引用
        • const修饰函数参数
        • const修饰函数返回值
        • const修饰类成员变量
        • const修饰类成员函数
        • const修饰类常量对象
        • const和#define的区别
        • 使用const的一些建议
      • extern
      • pointer
      • static
      • volatile
      • inline
      • assert
      • void
      • __global__
  • Performance Engineering

  • Misc

  • Reading Notes

  • Wiki
  • Lean in c++
  • Phase_0:Glimpse
Quincy Jet
2021-08-05
Content

const

一些const关键字常见的情况

# const修饰一般变量

const int a = 7; 
int b = a; // 正确
a = 8;    // 错误,不能改
1
2
3

即使用指针修改也是不可以的:

#include<iostream>
using namespace std; 
int main(void)
{
    const int  a = 7;
    int  *p = (int*)&a;
    *p = 8;
    cout<<a;  // 这里仍然输出a=7
    system("pause");
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

如果需要修改, 可以通过用volatile来修饰const,

#include<iostream>
using namespace std;
int main(void)
{
    volatile const int  a = 7;
    int  *p = (int*)&a;
    *p = 8;
    cout<<a; // 这里输出a=8
    system("pause");
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

# const修饰指针

Const 在指针的不同位置, 代表的含义也不一样, C++ primer里面会分为顶层const和底层const, 顶层const指指针本身是个const, 底层const指指针所指的对象是个const:

int* const x  = &y;                 //顶层const: const指针 --> 指针指向的地址不能做修改
const int* x = &y;                  //底层const: const对象 --> 变量的指向内容不能做修改, 
    							  	// y为一个const变量, 或者一个常规变量提升为一个const变量
const int* const x  = &y;           //Both两者都不能做修改
1
2
3
4

# const修饰引用

const引用就是指向const对象的引用,普通变量可以绑定到const 引用, 但是const变量不可以绑定到普通的引用上

int var1 = 1, var2 = 2;
int &a = 0; // 一般引用无法绑定到字面值常量
const int &b = 0; //const引用可以绑定字面常量值
int &c = var1 + var2; //错误,左值引用不可绑定右值, var1+var2为右值
const int &d = var1 + var2; //const引用可以绑定右值
1
2
3
4
5

# const修饰函数参数

传入const变量,一般这种情况不需要 const 修饰,因为函数会自动产生临时变量复制实参值。

传入const指针和const引用, 可以防止传入引用或指针改变原来的实参值

#include <iostream>
using namespace std;

void func(const int &a){
    int &b = a;
    b = 10;
}

int main(){
    int a = 0;
    func(a);
    cout << a << endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# const修饰函数返回值

const 修饰内置类型的返回值,修饰与不修饰返回值作用一样。

const 修饰自定义类型的作为返回值,此时**返回的值不能作为左值使用,既不能被赋值,也不能被修改。**这时候返回值为一个常量值,可以降低用户错误而造成的意外

#include <iostream>
#include <string>
using namespace std;
class A
{
private:
    int _a;
    string _str;
public:
    A(int a, string str):_a(a), _str(str){}
    const A operator+(const A &rhs);

    friend ostream &operator<<(ostream &os, const A &a)
    {
        os << a._str << " : " << a._a;
        return os;
    }
};

const A A::operator+(const A &rhs)
{
    return A(this->_a + rhs._a, this->_str + rhs._str);
}

int main(int argc, char *argv[])
{
    A a1(1, "a1");
    A a2(2, "a2");
    A a3(3, "a3");
    cout << (a1 + a2) << endl;
    (a1 + a2) = a3;   //错误, 但是如果去掉const,这里会有怎样的变化
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

const 修饰返回的指针或者引用,是否返回一个指向 const 的指针,取决于我们想让使用者做什么。

# const修饰类成员变量

这个const关键字在修饰成员变量时,与上文提及的使用雷同,const变量主要在初始化列表中赋值,并且不能进行修改。

    class object
    { 
        …
        const int value;         //const变量不能被修改 (int const value也可以)
        …
        object (int x): value(x) { } ;  // 构造函数初始化const变量
     } 
1
2
3
4
5
6
7

# const修饰类成员函数

const 修饰类成员函数,其目的是防止成员函数修改被调用对象的值,如果我们不想修改一个调用对象的值,所有的成员函数都应当声明为 const 成员函数。

**注意:**const 关键字不能与 static 关键字同时使用,因为 static 关键字修饰静态成员函数,静态成员函数不含有 this 指针,即不能实例化,const 成员函数必须具体到某一实例。

下面的 get_cm()const; 函数用到了 const 成员函数:

#include<iostream>
using namespace std;
class Test
{
public:
    Test(){}
    Test(int _m):_cm(_m){}
    int get_cm()const
    {
       return _cm;
    }
 
private:
    int _cm;
};
 
 
 
void Cmf(const Test& _tt)
{
    cout<<_tt.get_cm();
}
 
int main(void)
{
    Test t(8);
    Cmf(t);
    system("pause");
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

如果 get_cm() 去掉 const 修饰,则 Cmf 传递的 const _tt 即使没有改变对象的值,编译器也认为函数会改变对象的值,所以尽量将所有的不需要改变对象内容的函数都作为 const 成员函数。

如果有个成员函数想修改对象中的某一个成员怎么办?这时我们可以使用 mutable 关键字修饰这个成员,mutable 的意思也是易变的,容易改变的意思,被 mutable 关键字修饰的成员可以处于不断变化中,如下面的例子。

#include<iostream>
using namespace std;
class Test
{
public:
    Test(int _m,int _t):_cm(_m),_ct(_t){}
    void Kf()const
    {
        ++_cm; // 错误
        ++_ct; // 正确
    }
private:
    int _cm;
    mutable int _ct;
};
 
int main(void)
{
    Test t(8,7);
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

这里我们在 Kf() const 中通过 ++_ct; 修改 _ct 的值,但是通过 ++_cm 修改 _cm 则会报错。因为 ++_cm 没有用 mutable 修饰。

# const修饰类常量对象

常量对象所有成员默认添加了const修饰字,也就是所有的成员变量都不能进行修改。可以认为是关闭了写权限,所以const对象只能调用const成员函数,因为非const成员函数都有修改成员变量的权限。

#include <iostream>
using namespace std;

class A
{
public:
    A(){cout << "non-const" << endl;}
    void test() const{cout << "const" << endl;} //把这里的const去掉看看会发生什么
};

int main(int argc, char *argv[])
{
    const A a1;
    a1.test();
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# const和#define的区别

  1. 宏定义是在预编译阶段进行文本替换,而const是在编译阶段进行代码的语义约束。
  2. 由于二者所生效的阶段不同,所以能够起的作用也不同。const常量具有具体的类型,会在编译阶段进行类型检查,产生的代码显然会更加安全。(当然宏定义会更加灵活,可以定义代码或字符串,相对来讲如果要进行大量的宏替换,预编译时间会更长。)
  3. 宏定义很多时候是展开给立即数,多次替换需要多次分配内存,而const可以通过全局的符号表,仅保存一份copy就完事了。

# 使用const的一些建议

  1. 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

  2. 要避免最一般的赋值操作错误,如将const变量赋值;

  3. 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

  4. const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

  5. 不要轻易的将函数的返回值类型定为const;

  6. 除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

#C++
Last updated: 2023/03/11, 03:13:10
class vs. typename
extern

← class vs. typename extern→

Copyright © 2017-2023 Quincy Jet | MIT License
  • Auto
  • Light
  • Dark
  • Read