const是原C语言的关键字,修饰变量时表示只读的变量:
const int a = 10;
这就表明变量 a 是只读的变量。
但是编译器优化时会直接使用10来替换a,比如:
const int a = 10;
int *b = (int*)&a;//这里不能直接写&a对a取地址,因为指针可能改变a的值。
*b = 20;
cout<<a<<" "<<*b<<endl;
cout<<&a<<" "<<b;
结果:
在这里看到,即使b就是指向了a的内存,显示a的值时仍是10,这就是编译器直接拿a赋值时的10,替换了a。
如果我们添加关键字拒绝编译器优化修改:
volatile const int a = 10;
int *b = (int*)&a;
*b = 20;
cout<<a<<" "<<*b<<endl;
cout<<&a<<" "<<b;
这里的a的值确实被修改了,但是有一个更哈人的发现:
&a输出为了1。
这里是因为cout对“<<”操作符的重载不能准确运行,
可以在vs中看见重载的信息:
&a处被以bool类型重载了,导致输出1,表示true,当然,printf可以正常输出地址信息:
const还可以用在类的成员函数上面,表示在本成员函数上,不修改任何数据成员。如果产生修改,就会报错:
上面我们只说到const代表只读的变量,那么它是一个常量吗?
很明显,你已经用指针的方法修改过a的值了,尽管他被声明为了const,这里更直观的看一下:
用const int 的参数初始化array会报错,编译器认为const int a仍然是变量,而非常量。
当然,可以避免使用参数,而是在函数内定义一个const int使之通过编译:
这样就皆大欢喜了。
在C++11中,进一步的把“常量”和“只读”的语义分离开,const担任“只读”的语义,constexpr担任“常量”的语义。
constexpr修饰一个变量时,表示该变量为一个常量,例如:
constexpr int a = 10;
表示a为常量,且值为10;
而且声明const变量时,必须立即初始化。
也因此,函数的参数可以使用const修饰,但是不能使用constexpr修饰,因为无法立即赋值。(常量和只读的区别)
使用普通函数,无法初始化数组长度,因为这不是一个常量,而是变量。
int sum_two(int a, int b)
{
return a + b;
}
int main()
{
int s[sum_two(4, 5)] = { 3,2 };
}
不过这是VS2019的版本里面设置的,如果用DevCpp使用相似的操作,是可以编译的。(这个是编译器的问题,变量能直接初始化数组长度了,DevCpp中更直接可以这样,直接通过编译:)- >
当然,加上constexpr后,可以在编译时计算结果的函数会计算出结果并且以常量确定数组长度:
constexpr int sum_two(int a, int b)
{
return a + b;
}
int main()
{
int s[sum_two(4, 5)] = { 3,2 };
}
constexpr还能作用在类的构建函数中,不过这样的constexpr构造函数有更多的要求:
class Person
{
private:
double salary;
int age;
public:
constexpr Person(double s,int a):salary(s),age(a)
{}
};
1,构造函数的函数体是空的,成员全用列表构造。
2,只能使用字面值的类型。
(int,double,bool等类型为字面值类型,简单的说,能直接看出其值和类型,如string就不能算字面值类型)
使用string时报错: