一、c和c++区别
c语言const的特点:
1.c语言中const变量是只读的,本质还是变量
2.const修饰的变量在棧上分配空间
3.const修饰的全局变量在只读存储区分配空间
4.const只在编译期有用,运行期无用
总结:const修饰的变量不是真的常量,只是告诉编译器该变量不能出现在赋值符号的左边
c++中const在c的基础上进行了升级
1.当碰到const声明时,将常量纳入符号表
2.编译期如果发现使用常量,直接用符号表中的值进行替换
3.编译器若发现一下情况则给对应的常量分配存储空间
·对const使用extern
·对const使用&操作符
c++中const与宏的区别
1.const常量由编译器处理
2.编译器对const常量进行类型检查和作用域检查
3.宏由预处理处理,只是单纯的文本替换
关于c++中const&分配存储空间的代码
void test_const(){
const int a = 3;
int *p = (int *)&a;
*p = 5;
cout << "a = " << a << endl;
cout << "*p = " << *p << endl;
cout << "&a = " << &a << endl;
cout << "p = " << p << endl;
}
输出:
a = 3
*p = 5
&a = 0x7ffeec3a8a3c
p = 0x7ffeec3a8a3c
发现a的值为3,但是*p的值是5,验证了之前说的符号表中的值进行替换,而第二行用到了&a对a又分配了空间,*p则是改变了分配的空间的值
二、const修饰符的使用
1.const与指针的搭配
int a = 2, b = 3;
int * const p1 = &a;
const int * p2 = &a;
*p1 = 3; // 正常赋值
p1 = &b; // 报错,指针指向不能改变
*p2 = 3; // 报错,指针指向的值不能改变
p2 = &b; // 正常修改指针指向
2.const成员函数
·const对象调用
·不允许修改任何non-static成员变量
·常量性不同,可以进行重载
下面引用effective C++里面的例子
class TextBlock{
public:
TextBlock(string text):text(text){
}
const char& operator[](std::size_t pos) const{ // operator[] for const对象
return text[pos];
}
char& operator[](std::size_t pos) { // operator[] for non-const对象
return text[pos];
}
void setText(std::string text) const{
this->text = text;
}
private:
std::string text;
};
int main(){
TextBlock tb("hello");
const TextBlock tcb("world");
std::cout << tb[0];
std::cout << tcb[0];
tb[0]='x'; // 正常赋值
tcb[0]='x'; // 编译错误,返回的是const
tb.setText("abc"); // 编译错误,no viable overloaded '=' 将const去掉正常赋值
return 0;
}
1.const对象调用的是const声明的成员函数,
2.这里面两个函数都返回都是char&,如果返回都是char,那么也同样无法通过编译(原因是如果函数返回值是内置类型,那么改动返回值不合法,即使合法,也是一个副本,也不是你想要的结果)
3.setText方法设置成const则该成员函数不能修改任何non-static成员变量
有些时候,必须使用const成员避免一些莫名其妙的问题如:(a*b) = c;
class Complex{
public:
Complex(int real, int imag):real(real),imag(imag){
}
const Complex operator*(const Complex& comp1){
Complex c(0,0);
c.real = this->real * comp1.real - this->imag*comp1.imag;
c.imag = this->real * comp1.imag + this->imag * comp1.real;
return c;
}
void show(){
cout << this->real << " + " << this->imag << "i" << endl;
}
private:
int real;
int imag;
};
int main(){
Complex c1(2,3);
Complex c2(3,2);
Complex c3 = c1*c2;
c3.show();
Complex c4(1,1);
(c1*c2) = c4;
return 0;
}
(c1*c2) = c4这种代码不应该出现,但是编译器如果重载操作符opertor*不返回一个const的话,那么这种不合理现象只能在运行期发现,加上const则在编译器就能发现
3.const修饰函数参数
当函数参数为const的引用的时候,会创建临时变量:
·实参类型正确,但是不是左值
·实参类型不正确,但是可以转换成正确的类型
借用c++ primer plus例子
double refcube(const double &ra){
return ra*ra*ra;
}
double side = 3.0;
double * pd = &side;
double & rd = side;
long edge = 5l;
double lens[4] = {2.0,5.0,10.0,2.2};
double c1 = refcube(side); // 类型正确,左值
double c2 = refcube(lens[2]); // 类型正确,左值
double c3 = refcube(rd); // 类型正确,左值
double c4 = refcube(*pd); // 类型正确,左值
double c5 = refcube(edge); // 类型不正确,ra是一个临时变量
double c6 = refcube(7.0); // 类型正确,不是左值,ra是一个临时变量
double c7 = refcube(side+7.0); // 类型正确,不是左值,ra是一个临时变量
解释下,左值是可以被引用的值,例如:变量,数组,结构成员,引用,解除引用的指针都是左值,非左值包括字面量,和包含多项的表达式
正常情况下,接受引用参数的函数的意图是修改作为参数传递的变量,如果创建临时变量,则在函数体内修改,并不能改变原来的变量,显然这不是开发者的意图,c++在没有const的情况下就是这么做的,去掉const发现编译器报错。但是现在refcube函数传递的变量只是使用值,所以临时变量并不影响
引用参数声明为const理由有三个:
·避免无意中修改数据的编程错误
·使用const能处理const和non-const参数,否则只能接受non-const参数
·是函数能正确生成并使用临时变量