C语言中的类型转换
#include<stdio.h>
void Insert(size_t pos){
// int被转换为size_t,当传入的pos = 0时,会陷入死循环
int end = 10;
// 比较的时候end会隐式类型转换成size_t,再比较
while (end >= pos){
cout << end << "挪走" << endl;
--end;
}
}//数组索引最好使用size_t,因为它是非负的(无符号的)end从10开始变为-1后就被size_t视为一个很大的数了,然后进入函数体中还会继续减
int main(){
//1.溢出了
long val = 4566666666666661111113LL;
int ret = (int)val;
printf("%d\n", ret); // int 的取值范围是 -2,147,483,648 到 2,147,483,647。long val超出了int的范围。
//2.数据丢失精度
int i = 1233456789;
float j = i;
double jj = i;
printf("%f\n", j); // 1233456768.000000这与float底层存储精度有关
printf("%lf\n", jj); // 1233456789.000000 double就没有这个问题
//3.藏在背后的隐式类型转换导致意外的结果,如上insert函数
Insert(0);
return 0;
}
C++类型转换
class A{
private:
int a = 1, b = 1;
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
operator int(){
cout << "operator int()" << endl;
return a + b;
}
};
class AA{
};
class BB:public AA{
};
class CC{
public:
virtual void f(){}
int _a;
};
class DD:public CC{
public:
int _b;
};
void test_dynamic_cast(CC* p){
DD *pp = dynamic_cast<DD *>(p);
if(pp==nullptr){
cout << "dynamic_cast failed\n";
}
else{
cout << pp->_a << endl
<< pp->_b << endl;
}
}
int main()
{
//1.C++中使用单参的构造函数来进行类型转换
string s = "123456";//将C风格的字符数组转换为string对象,这是string的构造函数保证的
// 等价于string s("1233465");
// 这种方式是 C++ 对于字符串处理的一种常见做法,能够有效地避免 C 风格字符串的一些常见问题,如内存管理和缓冲区溢出。
//2.重载
A obj;
int l = obj;//这一句就是一个A类对象可以转为int
cout << l << endl;
int m = (int)obj;
cout << m << endl;
//A() operator int() 2 operator int() 2 ~A()
// C++依然兼容C语言的两种类型转换方式,但是为了加强类型转换时的可视性,C++引入了四种类型转换操作符,它们是一些进行类型转换时的命名建议,并不强制
//3.static_cast<>():有关联的类型之间进行转换
double d = 3.14;
int i = static_cast<int> (d);//静态转换
cout << i << endl;//3
//4.reinterpret_cast<>():强转
int a = 12;
int *p = reinterpret_cast<int *>(a);
//5.const_cast<>():删除const属性
const int n = 10;
int *p2 = const_cast<int *>(&n);
*p2 = 20;
cout << *p2 << endl;//20
cout << n << endl;//10//const的变量编译器知道无法修改,编译器直接在编译阶段就将10直接与使用n的地方联系起来了。所以其实n在内存中已经改了
// 如果是volatile const int n = 10;cout<<n<<endl;就是20。因为volatile要求编译器不要搞你那优化了,从内存去读取吧;
//6.赋值兼容
BB obj2;
AA obj1;
obj1 = obj2; // 子类对象赋值给父类对象
AA *pp = &obj2; // 子类地址赋给父类指针
BB &ref = obj2;
AA &reff = ref;//子类引用赋给父类引用
//父类指针现在指向子类,这是安全的;反之不安全。这主要是因为子类是在父类的扩展,空间和功能都扩展了
//为了解决这一问题,有了dynamic_cast<>():如果可以转换成功,就转换,反之返回nullptr
cout << "___________" << endl;
CC objC;
test_dynamic_cast(&objC);
}