const 修饰指针与变量

说说const int a, int const a, const int a, int const a, const int const a分别是什么 :::info

  1. const int a;
    2. const int a;
    3. int const
    a;
    4. int const a;
    5. const int
    const a; :::

参考解析如下: :::success

  1. const int a; //指的是a是一个常量,不允许修改。
    2. const int a; //a指针所指向的内存里的值不变,即(a)不变
    3. int const a; //同const int a;
    4. int const a; //a指针所指向的内存地址不变,即a不变
    5. const int
    const a; //都不变,即(*a)不变,a也不变 :::

const 应用到函数中

const 修饰函数形参,则在函数体中,能够保护原对象的属性(不会被修改);
const 修饰函数返回值,一般用于函数返回 const 引用,举例:

  1. const int &constRef(int &ref)
  2. {
  3. ref = 33;
  4. return ref;
  5. }
  6. void main()
  7. {
  8. int r = 22;
  9. constRef(r) = 44; // 报错: error: assignment of read-only location 'constRef(r)'
  10. }

const 引用,其指向的内容不允许改变。函数返回 const 引用时,不能通过函数返回的引用对实际对象进行任何修改,即使对象本身不是 const。
上述示例中, 虽然变量 r不是 const,但constRef函数返回了指向变量 r的 const 引用,不能通过该引用,对 r进行修改。

const 应用到类中

const 修饰成员变量:对于某个对象的生命周期内是常量,对于整个类是可以改变的。因为类可以创建多个对象,不同对象其 const 数据成员值是可以不同的。
所以不能在类的声明中初始化 const 数据成员:


5.0 追问:我用非 const 引用绑定到一个表达式,这样有什么问题吗?

编译报错,因为非 const 引用是左值,而表达式是右值

  1. int rx = 2;
  2. int &t = rx * 2;

以上代码会报错:

error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’

但是可以用 const 引用绑定到一个表达式:

  1. int rx = 2;
  2. const int &t = rx * 2;

5.1 追问:函数返回值为 const 值,外部将该函数返回值返回给非 const 变量,这样做有什么问题吗?

不会有什么问题

  1. const int constFunc()
  2. {
  3. int x = 10;
  4. return x;
  5. }
  6. void main()
  7. {
  8. int c = constFunc();
  9. c = 11;
  10. }

5.2 追问:对 const 成员变量在声明的时候初始化,这样做有问题吗?

举例: :::info class ConstClass
{
public:
ConstClass() : m_const_val(80)
{
// error: assignment of read-only member ‘ConstClass::m_const_val2’
m_const_val2 = 80;
}
private:
const int m_const_val; // OK
const int m_const_val2;
const int m_const_val3 = 80; // OK
}; :::

即 const 成员变量无法在构造函数体中初始化。可以在声明的时候初始化。

5.3 追问:关于 const 引用,声明一个 int 型 const 引用指向一个表达式, 这样写有问题吗?

没有问题。 初始化常量引用(const 引用)时允许用任意表达式作为初始值, 只要该表达式的结果能转换成引用的类型即可。
为什么呢? 看如下例子: :::info double dval = 3.14;
const int &ri = dval; :::

为了确保让 ri 绑定一个整数, 编译器会把上述代码编程如下形式: :::info const int temp = dval; // 由双精度浮点数生成一个临时整型变量
const int &ri = temp; // ri 绑定该临时量 :::

此时 ri 绑定一个 临时量 对象。即编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名对象。
此时编译器认为是将一个 const 引用绑定到一个 const 修饰 int 型常量
这样写语法上是没有问题的。

5.4 追问:那么声明一个 int 型非 const 引用指向一个表达式, 这样写有问题吗?

有问题。举例: :::info int i = 42;
int &ri = i * 2; // 错误, ri 是一个普通的非常量引用 :::

因为声明 ri 不是常量, 允许对 ri 赋值,但是此时 ri 绑定的是一个临时量(用完即销毁),是无法对临时量做赋值操作的。 所以将引用绑定到临时量上是非法的。

5.5 追问:const 成员函数内部访问非 const 数据成员,这样有问题吗?

没有问题。 const 成员函数可以访问所有成员变量。但是不能修改所有成员变量的属性。 :::info int Session::getSessionId() const {
this->_id = 10; // error: assignment of member ‘Session::_id’ in read-only object
return this->_id;
} :::

const 成员函数内部是只读的。

5.5.1 追问:我就想要在 const 成员函数内部修改成员变量,可行吗?

可行。 const 成员函数中如果实在想修改某个变量,可以使用 mutable 修饰该成员变量。 :::info class Session {
public:
void setId() const { this->mtId = 10; }
private:
mutable int mtId;
}; :::

5.5.2 追问: 如果想建立在整个类中都恒定的成员变量,是可行的吗?

用类中的枚举常量来实现或者 static const修饰。

5.6 追问:const 类对象访问非 const 成员函数,这样有问题吗?为什么?

有问题。因为没有被明确声明为 const 的成员函数被看做是将要修改对象中数据成员的函数,编译器不允许其被一个 const 对象调用。因此const对象只能调用const成员函数。

5.6.x 追问:如何将 const 类型变量转换为非 const 类型?

类型转换符 const_cast

5.6.x 追问:const 和 static 关键字修饰同一成员函数,这样有问题吗?

const 关键字和 static 关键字对于成员函数来说是不能同时使⽤的,因为 static 关键字修饰静态成员 函数不含有 this 指针,即不能实例化,const 成员函数⼜必须具体到某⼀个函数。

5.6.x 追问:有了解 constexpr 关键字吗?

常量表达式: 值不会改变并且在编译过程就能得到计算结果的表达式。
c++11标准规定将变量声明为 constexpr 类型以由编译器来验证变量的值是否是一个常量表达式。
constexpr 修饰指针时仅对指针本身有效:
const int p = nullptr; // p 是一个指向常量的指针
constexpr int
q = nullptr; // q 是一个指向整数的常量指针
即 constexpr 将它所定义的对象置为了顶层 const(常量指针)