欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

const

程序员文章站 2024-03-23 17:42:34
...

const

1. 修饰普通变量

用const修饰的变量是不变的,不能为其赋值。

const int a = 1;
int const a = 1;

2. 修饰指针

如果const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于
的右侧,const就是修饰指针本身,即指针本身是常量。
   因此,推荐使用int const* p,而不是使用const int* p(虽然两者意义完全一样),这样更容易理解。

int a = 10;
const int* p = &a;            // 指针指向的内容不能变
int const* p = &a;            // 同上
int* const p = &a;            // 指针本身不能变
const int* const p = &a;      // 两者都不能变
int const* const p = &a;      // 同上

3. 修饰引用

以下两种定义形式在本质上是一样的:

int a = 10;
const int& b = a; // 常引用:不能通过b去修改a的值
int const& b = a;

4. 修饰函数参数

用const修饰函数参数,传递过来的参数在函数内不可以改变。

void func (const int& n)
{
    n = 10;// 编译错误
}

5. 修饰函数返回值

用const修饰函数返回值的含义和用const修饰普通变量以及指针的含义基本相同。

const int* func() // 返回的指针所指向的内容不能修改
{
    // return p;
}

6. 修饰类成员变量

用const修饰的类成员变量,只能在类的构造函数初始化列表中赋值,不能在类构造函数体内赋值。

class A
{
public:
    A(int x) : a(x)  // 正确
    {
         //a = x;    // 错误
    }

private:
    const int a;
};

问题:类的构造函数初始化列表中赋值和函数体内赋值有啥差别?

7. 修饰类成员函数

用const修饰的类成员函数,在该函数体内不能改变该类对象的任何成员变量, 也不能调用类中任何非const成员函数。

class A
{
public:
    int& getValue() const
    {
        // a = 10;    // 错误
        return a;
    }

private:
    int a;            // 非const成员变量
};

8. 修饰类对象

用const修饰的类对象,该对象内的任何成员变量都不能被修改。
因此不能调用该对象的任何非const成员函数,因为对非const成员函数的调用会有修改成员变量的企图。

class A
{
 public:
    void funcA() {}
    void funcB() const {}
};

int main
{
    const A a;
    a.funcB();    // 可以
    a.funcA();    // 错误

    const A* b = new A();
    b->funcB();    // 可以
    b->funcA();    // 错误
}

9. 在类内重载成员函数

class A
{
public:
    void func() {}
    void func() const {}   // 重载
};

10. const与宏定义的区别

   const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。
   const常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
   另外,编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

#define PI 3.1415926535
const double PI = 3.1415926535;

11. const_cast

const_cast运算符用来修改类型的const或volatile属性。
一、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
二、常量引用被转换成非常量的引用,并且仍然指向原来的对象。

#include <iostream>
int main()
{
    const int a = 10;
    int* p = const_cast<int*> (&a);
    *p = 20;
    std::cout<<"p的地址: " << &p << "   ";
    std::cout<<"p的内容: " << p << std::endl;
    std::cout<<"*p的地址: " << &(*p) << "   ";
    std::cout << "*p的内容: " << *p << std::endl;    // 20
    std::cout << "a的地址: " << &a << "   ";
    std::cout << "a的内容: " << a << std::endl;     // 10, 原因见第10部分
    return 0;
}

// 名称    p                   a                   *p
// 数据    0x7ffeed81eaa8      10                  20
// 地址    0x7ffeed81eaa0      0x7ffeed81eaa8      0x7ffeed81eaa8