const_cast
const_cast转换符是用来移除变量的const或volatile限定符。
const int constant = 21;
int* modifier = const_cast<int*>(&constant); // 转换后constant的地址和modifier是一个地址
*modifier = 7;
上述转换也可以通过C语言的强制转换来执行:
const int constant = 21;
int* modifier = (int*)&constant;
*modifier = 7;
static_cast和dynamic_cast
参考:static_cast和dynamic_cast区别
C++中层次类型转换中无非两种:上行转换和下行转换
对于上行转换,static_cast和dynamic_cast效果一样,都安全;
对于下行转换:你必须确定要转换的数据确实是目标类型的数据,即需要注意要转换的父类类型指针是否真的指向子类对象,如果是,static_cast和dynamic_cast都能成功;如果不是static_cast能返回,但是不安全,可能会出现访问越界错误,而dynamic_cast在运行时类型检查过程中,判定该过程不能转换,返回NULL。
static_cast 上行转换 子类=》基类
用法:static_cast < type-id > ( expression )
子类总是包含父类的所有数据成员和函数成员,因此从子类转换到父类的指针对象可以没有任何顾虑的访问其(指父类)的成员。
上行转换:把派生类的指针或引用转换成基类的指针或引用
dynamic_cast 上行转换 & 下行转换
可以保证下行转换的安全性,何为安全性?即转换成功就返回转换后的正确类型指针,如果转换失败,则返回NULL。
image.png
image.png
转换测试代码:
class A {
public:
A() {}
~A() {}
virtual void fun() { cout << "A::FUN" << endl; }
};
class B {
public:
B() {}
~B() {}
virtual void fun() { cout << "B::FUN" << endl; }
};
class C : public A, public B {
public:
C() {}
~C() {}
};
int main()
{
C *c = new C;
printf("c: %p\n", c);
A* a = dynamic_cast<A*>(c);
A* a1 = static_cast<A*>(c);
A* a2 = (A*)c;
printf("dynamic_cast a: %p\n", a);
printf("static_cast a: %p\n", a1);
printf("C cast a: %p\n", a2);
printf("\n");
B* b = dynamic_cast<B*>(c);
B* b1 = static_cast<B*>(c);
B* b2 = (B*)(c);
printf("dynamic_cast b: %p\n", b);
printf("static_cast b: %p\n", b1);
printf("C cast b: %p\n", b2);
}
结果为:
image.png
即:上行(子=》基)转换中,是真实指向子类实例的指针中,强制转换、static_cast、dynamic_cast转换都成功,并且地址都一样。
菱形继承
image.png代码参考:c++ 类的内存布局 菱形继承
类D的内存布局如下:
image.png
int main()
{
D* d = new D(10);
printf("d: %p\n", d);
A* a = dynamic_cast<A*>(d);
printf("dynamic_cast a: %p\n", a);
B* b = dynamic_cast<B*>(d);
B* b1 = static_cast<B*>(d);
printf("dynamic_cast b: %p\n", b);
printf("static_cast b: %p\n", b1);
C* c = dynamic_cast<C*>(d);
C* c1 = static_cast<C*>(d);
printf("dynamic_cast c: %p\n", c);
printf("static_cast c: %p\n", c1);
}
image.png
dynamic_cast:“XXX”不是多态类型
class A {
public:
A() {}
~A() {}
};
class B {
public:
B() {}
~B() {}
};
class C : public A, B {
public:
C() {}
~C() {}
};
int main()
{
C *c = new C;
A* a = dynamic_cast<A*>(c);
B* b = dynamic_cast<B*>(c); // 此处编译失败,报:“dynamic_cast”:“C”不是多态类型
}
dynamic_cast必须使用虚继承表,而虚继承表实现的前提是父类中必须要有虚函数。
reinterpret_cast 重新诠释的转型
首先从英文字面的意思理解,interpret是“解释,诠释”的意思,加上前缀“re”,就是“重新诠释”的意思;cast在这里可以翻译成“转型”,这样整个词顺下来就是“重新诠释的转型”。
一个指向字符串的指针是如何地与一个指向整数的指针或一个指向其他自定义类型对象的指针有所不同呢?从内存需求的观点来说,没有什么不同!它们三个都需要足够的内存(并且是相同大小的内存)来放置一个机器地址。指向不同类型之各指针间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的对象类型不同。也就是说,指针类型会教导编译器如何解释某个特定地址中的内存内容及其大小。
C++类型转换之reinterpret_cast
网友评论