美文网首页
C++ const 关键字

C++ const 关键字

作者: long弟弟 | 来源:发表于2022-07-29 21:20 被阅读0次

本文是对const关键字的一个简单总结,测试环境IDE的是Xcode13.2.1

一、const及常量指针、指针常量、常指针常量

const是常量的意思,表示被修饰的变量不可修改
如果修饰的是类、结构体(的指针),其成员也不可以更改

先说结论:const修饰的是其右边的内容

验证:

#include <iostream>
using namespace::std;
//以下使用结构体验证(类与结构体的差异在C++中,只是访问权限的不同)

struct Date {
    int year;
    int month;
    int day;
};

int main(int argc, const char * argv[]) {
    // insert code here...
    const int age = 10;
    //int *a = &age; //“const int *”类型不能初始化“int *”类型
    //age = 20; //const修饰的变量不能修改
    //const int age1; //const修饰的类型必须在初始化时进行赋值
    
    Date date1 = {2021, 1, 2};
    const Date date2 = {2022, 2, 3};
    //date2 = date1; //const修饰的结构体本身不能被赋值
    //date2.year = 2019;//const修饰的结构体成员不能被赋值
    
    
    const Date *p = &date1;
    cout << "ori:" << p->year << p->month << p->day << endl;
    //p->year = 2011; //const修饰的是指针p,那么指针p即*p是不能改变的,但是p是可以修改的
    //(*p).month = 4;
    //*p = date2;
    p = &date2;
    cout << "modify:" << p->year << p->month << p->day << endl;
    
    //Date *date3 = &date2;//'const Date *'类型不能初始化'Date *'类型
    //与int *a = &age;同理
    
    int height = 10;
    int money = 20;
    {
        int *pp = &height;
        *pp = 30; //height = 30;

        pp = &money;
        *pp = 40; //money = 40;
    }
    cout << "height:" << height << endl;
    cout << "money:" << money << endl;
    const int *p0 = &height;
    int const *p1 = &height; //变量类型和const可以交换, p0和p1没有区别
    {
        const int *pp0 = &height;
        //*pp0是常量,pp0不是常量,常量指针
        cout << *pp0 << endl; //10
        //*pp0 = 50;//Read-only variable is not assignable
        pp0 = &money;
        cout << *pp0 << endl; //20
    }
    int * const p2 = &height;
    {
        int *const pp2 = &height; //pp2是常量,*pp2不是常量,指针常量
        *pp2 = 60; //height = 30;
        
        //pp2 = &money; //Cannot assign to variable 'pp2' with const-qualified type 'int *const'
    }
    cout << "height:" << height << endl;
    cout << "money:" << money << endl;
    
    const  int * const p3 = &height;
    int const * const p4 = &height;
    //p3和p4等价
    {
        const  int * const pp3 = &height;
        //第一个const修饰*pp3,*pp3的内容不能改 *pp3是常量,常量指针
        //第二个const修饰pp3,pp3的内容不能改 pp3也是常量,指针常量,常指针常量
        //*pp3 = 70;//Read-only variable is not assignable
        //pp3 = &money;//Cannot assign to variable 'pp3' with const-qualified type 'const int *const'
    }
    
    return 0;
}

问题:

以下五个指针分别是什么含义?

const int *p0 = &height;
int const *p1 = &height;
int * const p2 = &height;
const  int * const p3 = &height;
int const * const p4 = &height;

参考答案:
p0和p1等价,是常量指针
p2是指针常量
p3和p4等价,是常指针常量

二、const Reference常引用

前提

引用的本质就是指针,只是编译器弱化了它的功能,所以引用就是弱化了的指针

引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用
const必须写在&符号的左边,才算是常引用

const引用的特点

  1. 可以指向临时数据(常量、表达式、函数返回值等)
  2. 可以指向不同类型的数据
  3. 作为函数参数时(此规则也适用于const指针)
    可以接收const和非const实参(非const引用,只能接收非const实参)
    可以跟非const引用构成重载

了解:

当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量(汇编)

#include <stdio.h>
#include <iostream>
using namespace::std;

int test1() {
    return 100;
}
//这里sum参数要求必须是引用类型
//引用接收的是变量
int sum(int &v1, int &v2) {
    cout << "sum(int &v1, int &v2)" << endl;
    return v1 + v2;
}
//引用变成常引用就可以接收常量了,常引用可以接收变量和常量
int sum(const int &v1, const int &v2) {
    cout << "sum(const int &v1, const int &v2)" << endl;
    return v1 + v2;
}
//以上两个sum函数构成重载,换成*指针也使用,去掉引用或指针就报错
int main(int argc, const char * argv[]) {
    // insert code here...
    int age = 10;
    int height = 10;
    
    int &ref = age; // ref相当于age的别名,ref作为引用不能再指向其他变量(即不能当其他变量的别名)
    //&ref = height;
    
    ref = 20;
    cout << "age:" << age << endl << "ref:" << ref << endl;
    //常引用
    const int &ref2 = age;
    //int const &ref2 = age; //等价上一句
    //ref2 = 30; //不能再赋值
    cout << "ref2:" << ref2 << endl;
    //int & const ref3 = age;//Xcode报错:'const' qualifier may not be applied to a reference//'const'不能修饰引用 //VS编译器 可以编译通过 但因为引用指向本身不可更改,所以这里的const没有意义,等价于int &ref3 = age;
    
    //int *const p3 = &age;
    //p3是常量,p3不能修改,*p3可以修改即可以通过p3间接修改
    //可以把引用当做指针来看,所以在VS中可以ref间接修改,本来就是间接修改,所以没意义,可能是这个原因所以Xcode编译器直接报错
    
    //ref3 = 40;
    
    //int &ref4 = 10; //默认引用指向变量,因为本质是指针
    const int &ref5 = 10; //常引用可以指向临时数据(常量)
    int a = 1;
    int b = 2;
    const int &ref6 = a + b; //常引用指向表达式
    const int &ref7 = test1(); //常引用指向函数返回值
    const double &ref8 = age; //常引用指向了不同类型的数据
    
    cout << sum(a, b) << endl; //v1引用a
    //sum(10, 20); //v1引用10?
    //v1引用10的话,形参必须是const int &v1
    cout << sum(10, 20) << endl;
    const int c = 3;
    const int d = 4;
    cout << sum(c, d) << endl;
    
    age = 30;
    cout << "age:" << age  << "ref2:" << ref2 << endl;
    //引用的本质是指针,age变了,别名也变
    //输出age:30ref2:30
    cout << "age:" << age << endl << "ref8:" << ref8 << endl;
    //输出age:30ref2:20,ref8指向不同数据类型产生临时变量
    return 0;
}

三、const成员

const成员:被const修饰的成员变量、非静态成员函数

const成员变量:

必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
非static的const成员变量还可以在初始化列表中初始化

const成员函数(非静态):

  1. const关键字写在参数列表后面,函数的声明和实现都必须带const//限制修改(非静态)成员变量
  2. 内部不能修改非static成员变量
  3. 内部只能调用const成员函数,static成员函数
  4. 非const成员函数可以调用const成员函数
  5. const成员函数和非const成员函数构成重载
  6. 非const对象(指针)优先调用非const成员函数
  7. const对象(指针)只能调用const成员函数、static成员函数
class Car {
public:
  const int m_price = 0;
  Car(): m_price(0) {}
  void display() const {
     cout << "price is " << m_price << endl;
  }
  void run() const;
};
void Car::run() const {
  cout << "Car::run()" << endl;
}

四、类型转换

static_cast<type>(expression)
//对比dynamic_cast,缺乏运行时安全检测
//不能交叉转换(不是同一继承体系的,无法转换)
//常用于基本数据类型转换、非const转成const
dynamic_cast<type>(expression)
//一般用于多态类型的转换,有运行时安全检测
reinterpret_cast<type>(expression)
//属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝
//可以交叉转换
//可以将指针和证书互相转换
const_cast<type>(expression)
//一般用于去除const属性,将const转为非const

相关文章

网友评论

      本文标题:C++ const 关键字

      本文链接:https://www.haomeiwen.com/subject/xvtpbrtx.html