关于C++中const关键字的总结


const主要是为了数据的保护。简单的理解,声明了const的对象或函数就成为常对象或函数,下面将具体分析用const修饰的对象,用const修饰的类成员,用const修饰的引用,用const修饰的指针,以及和const有关的类型转换const_cast。
const和static都是C++中数据共享和保护中重要的关键字,点此可以查看我上一篇关于static的总结。

一、用const修饰的对象

常对象的数据成员值在整个生存期间不能被改变,因此常对象必须被初始化且不能被更新。
常对象的声明方式为:const 类型说明符 对象名
例如:

const int a = 10;
class A{
public:
    A(int i,int j):x(i),y(j){}
private:
    int x,y;
};

const A a(5,4);

二、用const修饰的类成员

类成员有两种:类成员函数和类数据成员。

1.类的常成员函数

由于C++会保护const对象不被更新,为了防止类的对象出现意外更新,禁止const对象调用类的非常成员函数。因此,常成员函数为常对象的唯一对外接口。
常成员函数的声明方式:类型说明符 函数名(参数表) const
下面给出一个类中含有常成员函数的例子:

#include <iostream>
using namespace std;
class Example{
public:
    Example(int x, int y){
        this->a = x;
        this->b = y;
    }
    void print();
    void print() const;
private:
    int a,b;
};
void Example::print() {cout<<"print():"<<a<<ends<<b<<endl;}
void Example::print() const {cout<<"print() const:"<<a<<ends<<b<<endl;}

int main() {
    Example e1(5,4);
    const Example e2(6,7);
    e1.print();
    e2.print();
    return 0;
}

输出结果如下:

print():5 4
print() const:6 7

有如下几个要点:

  1. 常成员函数的定义和声明都要含有const关键字;
  2. 一个函数是否含有const关键字可以作为重载函数,const对象默认调用const函数,非const对象默认调用非const函数,如果没有非const函数,也可以调用const函数;
  3. const函数中不能更新目的对象的任何成员(mutable修饰的变量除外,这里不展开阐述),以此方法来保证const对象不被修改。

2.类的常数据成员

类的数据成员不能在任何函数中被赋值或修改,但必须在构造函数中使用初始化列表的方式赋初值。
举个例子,刚才的类如果a, b为常数据成员,则应该改写为如下形式:

class Example{
public:
    Example(int x, int y):a(x),b(y){} //初始化列表方式赋初值
    void print();
    void print() const;
private:
    const int a,b;
};
void Example::print() {cout<<"print():"<<a<<ends<<b<<endl;}
void Example::print() const {cout<<"print() const:"<<a<<ends<<b<<endl;}

如果为静态常数据成员,由于不属于具体对象,所以不能在构造函数里赋值,仍然应该在类外赋值。特别地,如果静态常量为整数或枚举类型,C++允许在类内定义时指定常量值。
比如以下两种方式均合法:

class Example{
public:
    Example(int x, int y):a(x),b(y){}
    void print();
    void print() const;
private:
    const int a,b;
    static const int c = 10; //静态常量
};
class Example{
public:
    Example(int x, int y):a(x),b(y){}
    void print();
    void print() const;
private:
    const int a,b;
    static const int c; //静态常量
};
const int Example::c = 10;

三、用const修饰的引用

常引用所引用的对象不能更新,使用方法为:const 类型说明符 &引用名
非const引用只能绑定非const对象,const引用可以绑定任意对象,并且都当做常对象。
常引用经常用作形参,防止函数内对象被意外修改。对于在函数中不会修改其值的参数,最好都声明为常引用。复制构造函数的参数一般均为常引用。
仍然是上面那个例子:

class Example{
public:
    Example(int x, int y):a(x),b(y){}
    Example(const Example &e):a(e.a),b(e.b){} //复制构造函数
    void print();
    void print() const;
private:
    const int a,b;
    static const int c = 10;
};
void Example::print() {cout<<"print():"<<a<<ends<<b<<endl;}
void Example::print() const {cout<<"print() const:"<<a<<ends<<b<<endl;}

四、用const修饰的指针

1.指针常量

指针常量的意思是指针本身的值不能改变,意思是指针指向的地址不可以改变,但地址里的值可以改变。事实上,数组的名称就类似于一个指针常量,不可以被重新赋值。
声明方式:类型说明符 * const 变量名
举个例子:

int a = 10;
int b = 5;
int * const p1 = &a;
p1 = &b; //不合法
*p1 = b; //合法

2.常量指针

意思是不能通过指针来为对象重新赋值,但是指针本身可以指向另外的对象。
声明方式:const 类型说明符 * 变量名
举个例子:

int a = 10;
int b = 5;
const int* p2 = &a;
p2 = &b; //合法
*p2 = b; //不合法

五、补充一点const_cast的知识

简单来说,const_cast可以将常指针或常引用的const属性去除,注意:const_cast不用来将常对象转换为普通对象。
举个例子:

const int a = 4;
const int * p = &a;
int * m = const_cast<int*>(p);
* m = 5;
cout<<" a:"<<a<<ends<<&a<<endl;
cout<<"*p:"<<*p<<ends<<p<<endl;
cout<<"*m:"<<*m<<ends<<m<<endl;

输出结果:

 a:4 0x61ff04
*p:5 0x61ff04
*m:5 0x61ff04

可见,const_cast并没用真正修改a中的值,只是修改了m和p指针中的值,并且它们指向的是同一块空间。
const_cast的一个安全用法是,在类中的一个非常成员函数中,调用重载的常成员函数,以此来实现代码重用。
再举个例子:

const int & get_element(int n) const{
    if(n>=0 && n <len){
        throw "invalid memory visit";
    }
    return element[n];
}
int & get_element(int n){
    return const_cast<int &>(
            static_cast<const Array *>(this)->get_element(n)
            );
}

这是一个类中的两个同名函数,第一个函数仅供const对象调用,非const的函数为了重用const函数的代码,需要先将当前对象的指针转化为const类型,以此调用const函数,然后再将返回的结果用const_cast去除const属性,返回的引用就是可修改的了。

在C++中,数据的共享和保护机制是一个很重要的特性。因此static和const的用法非常复杂也非常丰富,要想在实际操作中完全正确使用这两个关键字,还是需要多加练习。

发布了6 篇原创文章 · 获赞 22 · 访问量 7242
App 阅读领勋章
微信扫码 下载APP
阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 创作都市 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览