1.C方式强制类型((Type)(a))转换存在的问题
(1)任意类型之间都可以进行转换,编译器很难判断其正确性
(2)在源码中无法快速定位所有使用强制类型转换的语句
C++中的强制类型转换,语法:xxx_cast<Type>(a)
(1)static_cast
用于基本类型间的转换,不能用于基本类型指针间的转换,用于有继承关系类对象之间的转换和类指针之间的转换
(2)const_cast
用于去除变量的只读属性,强制转换的目标类型必须是指针或引用
(3)dynamic_cast
用于有继承关系的类指针间的转换,用于有交叉关系的类指针间的转换,具有类型检查的功能,需要虚函数的支持
通过子类指针去指向父类指针
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}
virtual void func()
{
cout << "Base::func()" << endl;
}
virtual ~Base()
{
cout << "Base::~Base()" << endl;
}
};
class Derived : public Base
{
public:
virtual void func()
{
cout << "Derived::func()" << endl;
}
};
int main()
{
Base* p = new Base; //初始化父类指针
Derived* pd = dynamic_cast<Derived*>(p); //由于父类指针指向的是父类,只有父类虚函数表,没有子类的虚函数表,所以转换失败
//如果使用static_cast或者reinterpret_cast,则能成功,调用pd->func则打印Base::func()
//pd->func(); //由于pd=0,所以这里会程序崩溃
cout << "pd = " << pd << endl; //转换失败,打印 0
delete p;
p = reinterpret_cast<Base*>(new Derived); //等价于p = (Base*)new Derived; 或者 p = reinterpret_cast<Base*>(new Derived)
//或者static_cast
pd = dynamic_cast<Derived*>(p); //由于父类指针指向的是子类,所以有子类虚函数表
pd->func(); //打印"Derived::func()"
cout <<"pd = " << pd <<endl; //转换成功,打印地址值
delete p;
return 0;
}
- 父类(无虚函数)强制转为子类时,可以用static_cast或者reinterpret_cast进行强转
(4)reinterpret_cast
用于指针类型间的转换,用于整数与指针类型间的强转
#include <stdio.h>
void staic_cast_demo() {
int i = 0x12345;
char c = 'c';
int* pi = &i;
char* pc = &c;
c = static_cast<char>(i);
// pc = static_cast<char*>(pi); //error,不能用于基本类型指针间的转换
}
void const_cast_demo() {
const int& j = 1; //只读变量
int& k = const_cast<int&>(j); //去除只读变量,可以通过k修改变量的值
const int x = 2; //常量,存在符号表里
int& y = const_cast<int&>(x); //内存会给这个常量分配一个临时的空间,并且y指向这块空间
// int z = const_cast<int>(x); //error,目标类型必须是指针或引用
k = 5;
printf("k=%d\n", k); //5
printf("j=%d\n", j); //5
y = 8;
printf("x=%d\n", x); //2
printf("y=%d\n", y); //8
printf("&x=%p\n", &x); //&x=0000006DB754F964
printf("&y=%p\n", &y); //&y=0000006DB754F964
}
void reinterpret_cast_demo() {
int i = 0;
char c = 'c';
int* pi = &i;
char* pc = &c;
pc = reinterpret_cast<char*>(pi);
pi = reinterpret_cast<int*>(pc);
pi = reinterpret_cast<int*>(i);
// c = reinterpret_cast<char>(i); //error,不能用于基本类型间的转换
}
void dynamic_cast_demo() {
int i = 0;
int* pi = &i;
// char* pc = dynamic_cast<char*>(pi); error,只能用于有继承关系的类指针间的转换
}
int main() {
staic_cast_demo();
const_cast_demo();
}
2.const什么是只读变量,什么是常量?
(1)只有用字面量初始化的const常量才会进入符号表
const int x=1;
(2)使用其他变量初始化的const常量仍然是只读变量
const int& rx=x;
(3)被volatile修饰的const常量是易变的,因此不会进入符号表
即在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理,只读变量仅仅意味着被const修饰的变量不能出现在赋值符号左边
#include <stdio.h>
int main() {
const int x = 1;
const int& rx = x;
int& nrx = const_cast<int&>(rx);
nrx = 5;
printf("x=%d\n", x);
printf("rx=%d\n", rx);
printf("nrx=%d\n", nrx);
printf("&x=%d\n", &x);
printf("&rx=%d\n", &rx);
printf("&nrx=%d\n", &nrx);
volatile const int y = 2; //加了volatile就是只读变量
int* p = const_cast<int*>(&y);
*p = 6;
printf("y=%d\n", y); //6
printf("p=%p\n", p); //p=000000D6682FF8D4
const int z = y;
p = const_cast<int*>(&z);
*p = 7;
printf("z=%d\n", z);
printf("p=%p\n", p);
char c = 'c';
char& rc = c;
const int& trc = c; //引用的类型不同,则会生成一个新的只读变量,即trc是只读变量
rc = 'a';
printf("c=%c\n", c);
printf("rc=%c\n", rc);
printf("trc=%c\n", trc);
}
运行结果:

3.引用与指针的关系
指针:
(1)指针是一个变量,值为一个内存地址,不需要初始化,可以保存不同的地址
(2)通过指针可以访问对应内存地址中的值
(3)指针可以被const修饰为常量或只读变量
引用:
(1)引用只是变量的一个新名字,对引用的操作都会传递到代表的变量
(2)const引用使其代表的变量具有只读属性
(3)引用必须在定义时初始化,之后无法代表其他变量
#include <stdio.h>
int main() {
// const 常量
const int c = 0; //const局部变量
int* p = (int*)&c; //使用&操作符,会分配空间 int* p = (int*)&c -> const int& p = c;
*p = 5;
printf("c = %d,*p=%d\n", c, *p); // c = 0,*p=5 实际没有改变c自身的值。
// const 只读变量 (一般用在引用或者指针上)
int d = 1; // 临时变量,自身可读写
const int& p2 = d; // 其实这个p2 是个只读变量(可以通过const_cast去更改)
int& p3 = const_cast<int&>(p2);
p3 = 100;
printf("d = %d p2 = %d\n", d, p2); //d = 100 p2 = 100 实际目标d被改变了,因为d是个可读写的变量。
//所以引用修饰的const只是个标志,到底能不能更改目标,需要引用的目标类型是否是const
const int d2 = 1; // 引用的目标类型是const
const int& p4 = d2; // 其实这个p4 是个只读变量(可以通过const_cast去更改)
int& p5 = const_cast<int&>(p4);
p5 = 100;
printf("d2 = %d p4 = %d\n", d2, p4); //d = 100 p2 = 100 实际目标d2没有改变,因为d2是个常量。
return 0;
}