C++基础面试问题之const(非常重要!!!很考验基础!!!尤其是校招生,没有工程经验,尤其需要关注!!!)

const的语义为只读。修饰的值不能改变,必须在定义时就给它赋予初值本文将通过实际代码来理解这句话。

1.普通变量前加const

 void testConstVar(){
        int j = 20;
        const int i = j;    //const变量初始化时可以用非const变量赋值
        j = i;              //非const变量可以用const变量赋值
        j = 10;
        cout<<i<<','<<j<<endl;	//20,10

        const int x = 10;  //const变量初始化时可以用常量赋值
        int y;
        x = y; //err!const变量初始化后不能被赋值,这里是用非const变量测试
        const int z = 20; 
        z = x;    //err!const变量初始化后不能被赋值,这里是用const变量测试
    }

小结:对于加了const关键字的变量,其定义时必须初始化,无论是const还是非const变量都可以对其进行初始化;而对于初始化了的const变量,不能再被赋值

2.与函数关联的const

2.1 在函数返回值前加const

考虑一个如下函数

const int getNum(){
    int i;
    return i;
}

对它进行如下调用

void callGetNum(){
    std::cout<<typeid(getNum()).name()<<std::endl;	//我是在win下用g++编译的,打印出来是i,表示的是int。如果是用visual studio集成开发环境的话可以用__typeof__(var)宏(其中var是变量)打印类型。
    int ret = getNum(); 
    cout<<ret<<endl;    //0
    const int cret = getNum();
    cout<<cret<<endl;   //0
    const int& ref = getNum();
    cout<<ref<<endl;    //0
    auto aret = getNum();
    cout<<aret<<endl;   //0
}

小结:可以看到,用int,const int,const int& ,auto类型的都能接收到,那在函数返回值前加const还有什么意义呢?在这里const是用于说明getNum返回的是一个const int,也就是函数的设计者希望不要改变函数的返回值,作为调用者,最好应该使用const int& 接收。看一下接收后的情况

void callGetNum(){
    std::cout<<typeid(getNum()).name()<<std::endl;
    int ret = getNum(); 
    cout<<ret<<endl;    //0
    const int cret = getNum();
    cout<<cret<<endl;   //0
    int& ref = getNum();	//err! 返回值是const int,引用类型不能是非const
    const int& cref = getNum();
    cout<<cref<<endl;    //0
    auto aret = getNum();
    cout<<aret<<endl;   //0

    ret = 10;	
    cret = 10;	//err! cret是const,初始化不能再被赋值
    cref = 10;   //err! 不仅仅因为ref是const而不能被赋值,还因为ref是引用,也就是右值
    aret = 10;
}

从上可以看到用const int&接收更符合函数设计者的意图,虽然用cret接收也能实现函数的返回值不被改变,但cret是左值,开辟了新的内存,而cref是右值,是函数返回值的引用,与函数设计者要表达的意思是一致的。

2.2 在函数参数中加const

考虑如下函数

int getNum_1(const int i){
     //int i;
     //i = 10;	//err! 传入的是const,不能改变
     return i;
}

函数形参加const表示函数设计者不希望改变函数调用者传入的实参,考虑如下调用

void callGetNum_1(){
     int a = 10;
     const int b = 10;
     cout<<getNum_1(a)<<endl;	//10
     cout<<getNum_1(b)<<endl;	//10
}

可以看到,无论是用普通的变量还是const变量,都没错,这与const变量(形参i)初始化时可以用const或非const变量赋值一致,从这可能还看不出在形参前加const的用处,但当形参是指针或引用类型时,就很有必要了,在后面再做详细说明。

2.3 const在函数体后面

首先非成员函数上是不能这样使用的,必须在成员函数上才能使用,const在函数体后面,表示是类的常成员函数考虑如下类

class GetNum{
    int i = 10;
public:
    int getNum() const {
        //i = 20;	//err! 类的成员不能改变
        return i;
   }
};

做如下调用

void callGetNumClass(){
    GetNum cn;
    cout<<cn.getNum()<<endl;	//10
}

在类中加入普通成员函数和常成员函数,新的类定义如下

class GetNum{
    int i = 10;
    int static j;
public:
    static int getStaticNum(){
        return j;
    }
    void changeNum(){
        i = 20;
    }
    void printNum()const{
        cout<<i<<endl;
    }
    int getNum() const {
        //i = 20;
        //changeNum();	//err! 常成员函数只能调用常成员函数
        printNum();
        cout<<"in getNum fun: "<<"call getStaticNum fun val is "<<getStaticNum()<<endl;
        return i;
   }
};

int GetNum::j = 1;

做如下调用

void callGetNumClass(){
    GetNum cn;
    cn.getNum();
    cn.changeNum();
    cn.getNum();
    cn.getStaticNum();
}

结果如下

10
in getNum fun: call getStaticNum fun val is 1
20
in getNum fun: call getStaticNum fun val is 1

可以看到,常成员函数是可以调用常成员函数和静态成员函数的。这里的静态成员函数是个例外,也就是说常成员函数没有对静态成员变量进行限制。

2.4 在*左边或右边加const

2.4.1常量指针

常量的指针,是底层const,即指针指向的是一个只读的对象。const在*左边,靠近数据类型。
示例:

int a = 10;
int b = 20;
const int * pa = &a;	//int const * pa = &b;
pa = &b;	//pa的值可变
cout<<*pa<<endl;    //20 
2.4.2指针常量

指针类型的常量,是顶层const,指针常量只能在定义时初始化,之后不能改变。const在*右边,靠近变量名。

int a = 10;
int * const pa = &a;
*pa = 20;	//pa指向的对象值可变
cout<<*pa<<endl;    //20
2.4.3修饰引用

表示引用的值是常量,不能通过引用修改。

void testConstRef(){
    int a = 10, b = 20, c = 30;	//引用的对象必须初始化
    const int& ref_a = a;
    //ref_a = 15;	//err!
    cout<<ref_a<<endl;
    int const& ref_b = b;
    //ref_b = 25;	//err!
    cout<<ref_b<<endl;
    /*int & const ref_c = c;	//err! 引用本质上是一个常量指针,const加在这里是语义冲突的
    ref_c = 35;
    cout<<ref_c<<endl;*/
}

注:关于引用的一个注意点,引用是变量的别名,必须初始化,从一而终不可变,不存在指向空值的引用。

int a = 10, b = 20;
const int& cref_a = a;
int& ref_a = a;
cout<<ref_a<<endl;	//10
cout<<cref_a<<endl;	//10
//ref_a = 15;
ref_a = b;			//注意!这里不是改引用绑定,ref_a绑定的还是a,只是它的值现在通过b赋予
cout<<ref_a<<endl;	//20	//a的值现在是20
cout<<cref_a<<endl;	//20	//a的值现在是20

关于const的位置大概就这么多,它们之间的组合就不再一一介绍了,如有错误或遗漏,欢迎交流补充,谢谢!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值