C语言类型转换
1.
void Test1()
{
int i = 1;
//隐士类型转换(意义相近)
double d = i;
printf("%d %.2f\n", i, d);
int* p = &i;
//显示类型转换(意义不相近,转换后值有意义)
int address = (int)p;
printf("%p %d\n", p, address);
printf("%x %d", p, address);
}
2.
void Insert(size_t pos,char ch)
{
size_t _size = 10;
size_t end = _size - 1;
while (end >= pos)
{
//_str[end + 1] = _str[end];
--end;
}
}
void Test1()
{
Insert(5, 'a');
Insert(0, 'a');//
}
在这里调用的时候就出问题,end不会小于0,改为int end也不行;
通过监视发现,明明end变成-1,但循环仍会进去,这里其实就是比较的时候发生了隐式类型转换,比较的时候end由int变为unsigned int;
此时C++后来在这里做了一些新的方法(旧的不能改)------四种类型转换,接着往下看…
四种类型转换
提出的目的,1
了兼容C语言,由有自己特有的方式,2
显示类型混在一起,不清晰;
3
C++期望不要用这些对象,而是用以下四种类型转换替代它们;
前三种为兼容C语言强制类型转换
static_cast
静态转换(对应隐式类型转换,即意义相近的类型)
用于明确转换一种数据类型为另一种,包括基本数据类型、类指针和引用等。
可以用于类层次结构中的向上和向下转换,但不会进行运行时检查,因此可能不安全。
总结:它有错误会在编译时指出,运行时不会起作用
double d = 3.14;
int i = static_cast<int>(d);
reinterpret_cast
重新解释转换
对p的意义重新解释
用于将一个指针或引用转换为另一种不同类型的指针或引用。
它不会进行类型检查或添加/移除任何常量性,仅仅是重新解释数据
。
非常危险,一般情况下应该避免使用,除非非常清楚转换的含义和后果。
int num = 10;
void* voidPtr = #
int* intPtr = reinterpret_cast<int*>(voidPtr);
const_cast
常量转换(对应强制类型转换)
用于去除指针或引用的常量性。
可以用于添加或移除常量性
,但不应该用于修改原本非常量对象
的值。
int main()
{
const int a = 2;
int* p = const_cast<int*>(&a);
*p = 5;
cout << a << endl;
cout << *p << endl;
return 0;
}
原因:编译器优化,它对const变量认为不会变,故而直接加载到了寄存器(有的编译器直接用宏那种处理方式直接替换,如vs),读的时候它会去寄存器去取(即使a的值在内存中已被修改);而调试器拿数据的时候在内存中取数据;
补:调试的时候,是另一个进程去取调试信息的;
看上面截图,截图红色框有问题,看底下的 push 2
这里流中直接将2压入栈中的。
如何处理呢?加关键字volatile
,让编译器不要写死
dynamic_cast
动态转换(C++独有),向下转换
于在类层次结构中进行安全的向上和向下转换。
只能用于指向对象的指针和引用,并且只能用于具有虚函数的类
。
在向下转换时,如果转换是有效的
,则返回指向目标类型的指针
;否则返回空指针
。
先看之前的类型转换,都会产生临时变量
C语言强转
C++安全转换
class A
{
public:
virtual void f(){}
int _a = 0;
};
class B :public A
{
public:
int _b = 0;
};
void fun(A* pa)
{
B* pb = dynamic_cast<B*> (pa);
//B* pb = (B*)pa;
if (pb)
{
cout << "转换成功" << endl;
cout << pb->_a << ":" << pb->_b << endl;
}
else
{
cout << "转换失败" << endl;
cout << pa->_a << endl;
}
}
int main()
{
A* aa = new A;
B* bb = new B;
fun(aa);
fun(bb);
return 0;
}
这里相信已经很清楚的介绍了dynamic_cast,那接下来我们关于它的变幻,在进行深入玩转
class A1
{
public:
//virtual void f() {}
int _a = 0;
};
class A2
{
public:
//virtual void f() {}
int _a = 0;
};
class B :public A1,public A2
{
public:
int _b = 0;
};
int main()
{
B bb;
A1* ptr1 = &bb;
A2* ptr2 = &bb;
cout << ptr1 << endl;
cout << ptr2 << endl << endl;
B* pb1= (B*)ptr1;
B* pb2= (B*)ptr2;
cout << pb1 << endl;
cout << pb2 << endl << endl;
//B* pbb1 = dynamic_cast<B*>(ptr1);
//B* pbb2 = dynamic_cast<B*>(ptr2);
//cout << pbb1 << endl;
//cout << pbb2 << endl << endl;
return 0;
}
可见C语言的写法也会将切片的偏移量在向回转的时候,跳回去且不受虚函数限制;
RTTI
Run Time Type Identification:运行时类型识别
之前在智能指针学过一个RAII:资源获得初始化
;
typeid
:对象类型字符串
dynamic_cast
:识别父类指针是指向子类对象address
还是父类对象nullptr
decltype
:推导对象类型,可以用来定义别的对象