用const_cast将常指针转换成普通指针(用于通过迭代器修改容器内的值)
一. 函数描述:
const_cast < type-id > ( expression )
主要是用来去掉const属性,当然也可以加上const属性。主要是用前者,后者很少用。
去掉const属性:const_case<int*> (&num),常用,因为不能把一个const变量直接赋给一个非const变量,必须要转换。
const_cast < type-id > ( expression )
主要是用来去掉const属性,当然也可以加上const属性。主要是用前者,后者很少用。
去掉const属性:const_case<int*> (&num),常用,因为不能把一个const变量直接赋给一个非const变量,必须要转换。
加上const属性:const int* k = const_case<const int*>(j),一般很少用,因为可以把一个非const变量直接赋给一个const变量,比如:const int* k = j;
二. 使用范围:
1. 常量指针被转化成非常量指针,转换后指针指向原来的变量(即转换后的指针地址不变)。
1. 常量指针被转化成非常量指针,转换后指针指向原来的变量(即转换后的指针地址不变)。
class A { public: A() { m_iNum = 0; } public: int m_iNum; }; void foo() { //1. 指针指向类 const A *pca1 = new A; A *pa2 = const_cast<A*>(pca1); //常量对象转换为非常量对象 pa2->m_iNum = 200; //fine //转换后指针指向原来的对象 cout<< pca1->m_iNum <<pa2->m_iNum<<endl; //200 200 //2. 指针指向基本类型 const int ica = 100; int * ia = const_cast<int *>(&ica); *ia = 200; cout<< *ia <<ica<<endl; //200 100 }2. 常量对象(或基本类型)不可以被转换成非常量对象(或基本类型)。
void foo()
{
//常量对象被转换成非常量对象时出错
const A ca;
A a = const_cast<A>(ca); //不允许
const int i = 100;
int j = const_cast<int>(i); //不允许
}
三. 总结:
1. 使用const_cast去掉const属性,其实并不是真的改变原类类型(或基本类型)的const属性,它只是又提供了一个接口(指针或引用),使你可以通过这个接口来改变类型的值。也许这也是const_case只能转换指针或引用的一个原因吧。
2. 使用const_case添加const属性,也是提供了一个接口,来不让修改其值,不过这个添加const的操作没有什么实际的用途(也许是我认识太浅了)。
————————————————
版权声明:本文为CSDN博主「lwbeyond」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
{
//常量对象被转换成非常量对象时出错
const A ca;
A a = const_cast<A>(ca); //不允许
const int i = 100;
int j = const_cast<int>(i); //不允许
}
三. 总结:
1. 使用const_cast去掉const属性,其实并不是真的改变原类类型(或基本类型)的const属性,它只是又提供了一个接口(指针或引用),使你可以通过这个接口来改变类型的值。也许这也是const_case只能转换指针或引用的一个原因吧。
2. 使用const_case添加const属性,也是提供了一个接口,来不让修改其值,不过这个添加const的操作没有什么实际的用途(也许是我认识太浅了)。
————————————————
版权声明:本文为CSDN博主「lwbeyond」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
const int a = 3;
int *r = const_cast<int*>(&a);
(*r)++;
cout << a << endl;
int i = 3;
const int b = i;
int *r2 = const_cast<int*>(&b);
(*r2)++;
cout << b << endl;
int *r = const_cast<int*>(&a);
(*r)++;
cout << a << endl;
int i = 3;
const int b = i;
int *r2 = const_cast<int*>(&b);
(*r2)++;
cout << b << endl;
这两段代码做的事情非常类似,也就是通过const_cast修改了一个const修饰的int。唯一的不同是int a是直接赋值成了3,而int b是赋值成了另外一个也等于3的int。这两者其实并没有什么区别,对吧?但是当我们运行代码之后,神奇的事情发生了,
屏幕上输出的结果是这样的:
3
4
set<string>::iterator it = st.begin();
const_cast<string&>(*it) = "test";
for (auto it = st.begin(); it != st.end(); it++) {
cout << *it << endl;
}
老梁发现这个问题的时候是完全震惊的,查了好久的资料,才从大牛博客的只言片语当中找到了一点描述。原来是编译器针对第一种情况做了优化,因为a初始化时给的是一个常量,所以当我们输出的时候,编译器就直接取了3代替了它实际原本应该的值。
关于这个解释老梁也不能完全确认,
set<string> st{"hello", "world", "good"};set<string>::iterator it = st.begin();
const_cast<string&>(*it) = "test";
for (auto it = st.begin(); it != st.end(); it++) {
cout << *it << endl;
}
但是我们需要注意一点,我们这样强行修改其实是没有经过set原本的机制的。也就是说我们虽然改了元素的值,但是它在红黑树中的位置其实是没有变的。这样的结果就是会导致元素失去有序性,比如上面的结果输出的顺序是:"test","hello","world",按道理应该是按照字典顺序排序的。
这也是为什么C++ Primer里强烈建议大家不要修改set中元素值的原因,如果真的要修改,只能先删除再添加了。虽然这样会牺牲一点点性能,但至少可以保证set里的数据都是安全有序的。
//cosnt_cast 去掉类型中的常量性
//const_cast 中的类型必须是指针、引用或指向对象类型成员的指针
void test03(){
//对象指针
const Building* const_buding = new Building;
//const_buding->mA = 10; //const 修饰,不可修改
Building* nonconst_buding = const_cast<Building*>(const_buding);
nonconst_buding->mA = 10;
//引用
int a = 10;
const int& b = a;
//b = 10; //不可修改
int& c = const_cast<int&>(b);
c = 20;
cout << "a:" << a << endl;
//给指针加上 const 性
Building* nonconst_budingVal = new Building;
nonconst_budingVal->mA = 10; //可行
const Building* const_budingVal = const_cast<const Building*>(nonconst_budingVal);
//const_budingVal->mA = 20; //不可行
}