const_cast
在我们的coding当中,经常使用到const来修饰形参,主要是为了保证在函数里面不要对其进行修改,但是呢?这种操作也会导致以下情况:
class AA {
private:
int _val;
public:
int GetSize() { return 43; }
void SetVal(int val){ _val = val;}
int GetVal() {return _val;}
};
class BB {
public:
int GetSize() { return 33; }
bool isEauql(const AA &a) const {
AA &a1 = const_cast<AA &>(a);
BB &b1 = const_cast<BB &>(*this);
BB *c1 = const_cast<BB *>(this);
// 获取常量a的地址和获取将a转换成非常量后的地址
std::cout<<&a<<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d7088
std::cout<<&a1<<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d7088
// 转换const this指针变成非常量指针后,获取其地址
std::cout<<&c1<<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d7048
// 获取this指针的地址
std::cout<<this<<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d708f
// 转换const this指针变成非常量引用后,获取地址
std::cout<<&b1<<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d708f
// 不可以通过a去修改AA类中的属性值
a.SetVal(2);
// 可以通过转换常量a后的非常量引用a1来修改AA类中的属性值
a1.SetVal(2);
std::cout<<a1.GetVal()<<std::endl;
if (a1.GetSize() == b1.GetSize()) {
return true;
}
return false;
}
};
int main() {
BB b;
AA a;
std::cout << &a <<std::endl; // 编译运行后,得到地址为:0x7ffd8f5d7088
std::cout<<b.isEauql(a)<<std::endl;
}
分析上面的代码:
main函数
main函数中定义了两个类对象,分别是a和b,此时在内存的栈区域会给这两个变量开辟一块内存来存放它们。
isEqual函数
当对象b调用函数isEqual(a)之后,在isEqual函数中可以打印形参a的地址可以看到,这两个地址是一模一样的,这是因为引用只是给变量起了个别名,所以它们的地址是相同的,然后我们再打印通过const_cast转换a后的a1非常量引用的地址,可以看到这两个的地址是一致的(this和b1也是一致的),但是在实际的编译器地址中引用是需要占有一定内存的,这个内存的大小和指针大小一致,只是编译器做了一些手脚,让我们看他们的地址是一致的。
(1)我们定义了c1指针来指向const this指针转换成非常量的内存,可以看到这里的c1跟this的地址是不相同的,因为指针是自己占据了内存,所以我们可以通过转换后的c1来进行调用BB类中的属性或者方法函数,但是不能通过const this指针来调用BB类中的属性或者方法。
(2)我们定义的a1和b1这两个引用分别作为类对象a和this的非常量引用,虽然我们在打印a和a1的地址是一样的,b1和this的指针是一样的,但是在实际的编译器中a和a1,b1和this是不相同的,在实际的内存中是长这样的:
所以才导致我们a和this不能直接调用类中的属性和方法,因为它本身还是常量,而a1和b1就可以调用并且修改.