const 主要用来修饰数据成员、成员函数、类对象。
1.修饰指针情况
int b = 500;
const int * a = &b; //情况1
int const * a = &b; //情况2
int * const a = &b; //情况3
const int * const a = &b; //情况4
对于修饰指针的情况,只要看const 在 星号的左右即可,对于情况1和情况2是相同的。
当const在星号左边,即 const用来修饰指针所指向的变量,即指针指向常量(*a 不可以改变)。
例子如下
int b = 50;
const int * a = &b;
* a = 600; //错误
//可以修改b
b = 100; //*a 变成100
//也可以修改a的指向
int c = 200;
a = &c; //*a 变成200
//由于 a 不是常量,若不初始化也可以
const int * a;//正确
当const在星号右边,const修饰指针本身,即指针本身为常量(a 不能修改,即地址不能修改)。
例子如下:
int b = 50;
int * const a;//错误,由于指针a是常量,必须初始化
int * const a = &b;
b = 500; //正确,允许修改b
*a = 600;//正确,允许修改*a
a++;//错误,a不能改
对于情况4来说,指针的指向和本身均为常量,所以无法修改 *a 和 a 的,当然 b还是能修改的。如下:
int b = 50;
int const * const a = &b;
*a = 600; //错误,不允许修改*a
int c = 1000;
a = &c; //错误,不允许修改a
b = 200; //正确,可以修改b
2.当修饰数据成员的时候,初始化位置只能在参数列表里,被const修饰的数据成员,不能被修改。
#include <iostream>
#include<cstring>
using namespace std;
class A
{
public:
A(int v)
:val(v) //只能在参数列表里
{
//val=100; //error 被const修饰的数据成员,不能被修改。
}
void dis()
{
cout<<val<<endl;
}
private:
const int val;
};
int main()
{
A a(5);
a.dis();
return 0;
}
3.修饰成员函数
位置:函数声明之后,实现体之前。要求在声明和定义处都要有修饰。
意义:const 成员承诺,不会修改数据成员
能访问 const 和 非 const 数据成员,但不能修改非 const 数据成员。
只能访问 const 成员函数
(还可以构成重载):const对象只能调用const成员函数,非const对象优先调用非const成员函数,若无则可调用const成员函数,例子见第三类里的程序。
class A
{
public:
A(int v)
:val(v)
{
//val=100;
}
void dis() const
{
cout<<val<<endl;
//x=200; //error 不会修改数据成员
//print(); //error 不能访问 非const 成员函数
//print1(); //error 不能访问 非const 成员函数,不能修改非 const 数据成员。
print2(); //ok 只能访问 const 成员函数
}
void print()
{
}
void print1()
{
x=100;
y=200;
}
void print2()
{
}
void print2() const //构成重载
{
}
private:
const int val;
int x,y;
};
4.修饰类对象
const 修饰函数,是从函数的层面不修改数据。
const 修饰对象,是从对象的层面不修改数据。只能调用 const 成员函数
class A
{
public:
A(int v)
:val(v)
{
//val=100;
}
void dis() const
{
cout<<"void dis() const"<<endl;
}
void dis()
{
cout<<" void dis() "<<endl;
}
void print()
{
x=100;
y=200;
}
private:
const int val;
int x,y;
};
int main()
{
const A a(5);
//a.print(); //error
a.dis(); //ok,输出 void dis() const
A b(5);
b.dis(); //ok,输出 void dis(),但是如果没有 void dis() , void dis() const
return 0;
}
PS:在 C++ 中,mutable 是为了突破 const 的限制而设置的。被 mutable 修饰的变量,将永远处于可变的状态,即使在一个 const 函数中,甚至结构体变量或者类对象为 const,其 mutable 成员也可以被修改。
struct Test
{
int a;
mutable int b;
};
const struct Test test = {1,2};
test.a = 10; # 编译错误
test.b = 20; # 允许访问
class Test
{
private:
int a;
mutable int b;
public:
void func2() const
{
a++; # 编译错误,不允许修改a
b++; # mutable修饰后允许修改
}
};
这里出现了令人纠结的 3 个问题:
1、为什么要保护类的成员变量不被修改?
2、为什么用 const 保护了成员变量,还要再定义一个 mutable 关键字来突破 const 的封锁线?
3、到底有没有必要使用 const 和 mutable 这两个关键字?
保护类的成员变量不在成员函数中被修改,是为了保证模型的逻辑正确,通过用 const 关键字来避免在函数中错误的修改了类对象的状态。并且在所有使用该成员函数的地方都可以更准确的预测到使用该成员函数的带来的影响。而 mutable 则是为了能突破 const 的封锁线,让类的一些次要的或者是辅助性的成员变量随时可以被更改。没有使用 const 和 mutable 关键字当然没有错,const 和 mutable 关键字只是给了建模工具更多的设计约束和设计灵活性,而且程序员也可以把更多的逻辑检查问题交给编译器和建模工具去做,从而减轻程序员的负担。
版权声明:本文为博主原创文章,未经博主允许不得转载