1. C语言中的类型转换
expression,其中 type_name 是目标类型,expression是要转换的表达式。
void Test()
{
int i = 1;
// 隐式类型转换
double d = i;
printf("%d, %.2f\n", i, d);
int* p = &i;
// 显示的强制类型转换
int address = (int)p;
printf("%x, %d\n", p, address);
}
2. C++的类型转换
C语言中的类型转换都是内置类型之间的转换,到C++后,出现了类的概念,于是又多出了以下与类相关的转换:
- 内置类型 → 自定义类型,依赖构造函数
- 自定义类型 → 自定义类型,依赖构造函数
- 自定义类型 → 内置类型,依赖操作符重载
前两种比较简单,如下
class A
{
public:
A(const int& sta)
:_sta(sta)
{}
private:
int _sta;
};
int main()
{
A tmp = 10;
return 0;
}
第三种,则需要通过操作符重载来实现,如下
class A
{
public:
A(const int& a, const int& b)
:_a(a)
,_b(b)
{}
operator int()
{
return _a + _b;
}
operator double()
{
return _a - _b;
}
private:
int _a;
int _b;
};
int main()
{
A tmp(5, 10);
int t1 = tmp;
double t2 = tmp;
return 0;
}
通过操作符重载让类A
支持两种类型转换:A->int
和A->double
,格式为operator type_name (),operator type_name就可以完成到type_name类型的转换。注意的是,类型转换的返回值是固定的,所以operator type_name左侧不用写函数返回类型。
2.1 static_cast
它的作用包括:
- 基本数据类型之间的转换,如将
double
转换为int
。
int main()
{
double a = 5.5;
int b = static_cast<int>(a);
return 0;
}
- 类层次结构中的向上转型,即将子类类型的指针或引用转换为基类类型。
class Base
{
//...
};
class Derived : public Base
{
//...
};
int main()
{
Derived a;
Base* b = static_cast<Base*>(&a);
return 0;
}
- 指针或引用类型之间的转换,但不支持多态类型的向下转型。
int main()
{
void* a = new int;
int* b = static_cast<int*>(a);
return 0;
}
2.2 reinterpret_cast
- 将一个指针转换为整型
int main()
{
int* a = new int(5);
int b = reinterpret_cast<int>(a);
return 0;
}
- 在不同的指针类型之间进行转换
int main()
{
int* a = new int(5);
double* b = reinterpret_cast<double*>(a);
return 0;
}
2.3 const_cast
const_cast 是 C++ 中的一个类型转换运算符,用于移除或添加 const 或 volatile
限定符。需要注意的是,const_cast 中的类型必须是指针、引用或指向对象类型成员的指针。
它主要用于以下几种情况:
- 当你需要传递一个
const
对象到一个期望非const
参数的函数时,可以使用const_cast
来去除const
限定符。
void func(int& tmp)
{}
int main()
{
const int a = 5;
int* b = const_cast<int*>(&a);
func(*b);
return 0;
}
- 在某些设计中,可能需要修改一个原本声明为
const
的对象,这时可以使用const_cast
来去除const
限定符,但这种做法应该非常谨慎,因为它可能会导致未定义行为,尤其是当原始对象实际上是存储在常量内存区域时。
int main()
{
const int a = 5;
int* b = const_cast<int*>(&a);
*b = 10; // 修改常量对象的值
cout << "a:" << a << endl;
cout << "b:" << *b << endl;
return 0;
}
如上代码中a为const对象,我们使用const_cast
来去除 const
限定符得到b,并修改b的值为10,再打印出来时却发现a仍为5。为什么会这样呢?
实际上,C++的常量不存储在常量区,而是存储在栈区,而编译器会对const
变量优化,把const
变量放到寄存器中,后续只要访问变量a
,都去寄存器中查找。我们通过指针b修改的变量,其实修改的是栈区中的数据,没有修改寄存器的数据,因此访问a
还是从寄存器中读出了5。
为了解决这个问题,可以用volatile
关键字修饰const变量,此时就不会把常量存在寄存器中了。
int main()
{
volatile const int a = 5;
int* b = const_cast<int*>(&a);
*b = 10; // 修改常量对象的值
cout << "a:" << a << endl;
cout << "b:" << *b << endl;
return 0;
}
同样的可以使用 const_cast
来去除 volatile
限定符
int main()
{
volatile const int a = 5;
const int* b = const_cast<const int*>(&a);
return 0;
}
2.4 dynamic_cast
class Base
{
public:
virtual void func()
{}
};
class Derived : public Base
{
//...
};
int main()
{
Base a;
Derived b;
Base* c = dynamic_cast<Base*>(&b);//向上转型
Derived* d = dynamic_cast<Derived*>(&a);//向下转型
cout << "c:" << c << endl;
cout << "d:" << d <<endl;
return 0;
}
![](https://i-blog.csdnimg.cn/direct/3466b413219543789585048ae3ca4eec.png)
3.运行时类型信息(RTTI)
运行时类型信息(RTTI)是C++中的一项特性,它允许程序在运行时识别和检查对象的类型。