先看个笔试选择常考题,看下面代码,写出运行结果:
#include
using namespace std;
int main()
{
const int a = 10;
int*p =(int*) &a;
*p = 20;
cout << a << endl;
return 0;
}
输出结果是仍然是10,但是内存中已经是修改后的20。What fuck?事实胜于雄辩,我们知道在C++中被const修饰的变量就是常量,所以,这里显示使用了C语言的强制类型转换,达成了修改意愿。
C语言的中强制类型转换分为隐式类型转换和显示的强制类型转换。
直接看栗子
#include
using namespace std;
int main()
{
int a = 10;
double b = 20;
b = a;
cout << a << endl << b << endl;
system("pause");
return 0;
}
int类型的a赋值给double类型的b,是允许的,语法上认为,它们都是相近类型,都是表示数值,所以允许它们直接隐式类型转换。
如果你想把不相近类型强制转换,也许显示调用强制类型转换会有效果。
#include
#include
using namespace std;
int main()
{
int a = 10;
int*p = &a;
int b = (int)p;//把指针类型转换成整形
system("pause");
return 0;
}
简单了解了C语言的类型转换,我们再来看看这个题。既然强制类型转换了,为什么输出结果还是10呢?因为const,C++中,编译器认为const修饰的值是常量,所以它会将这个常量放在寄存器中,当需要使用时候,它就从寄存器直接取出来这个初始化时候的常量。
还真是这样,为了让这货好好干活,别再偷懒优化。我们可以在a变量前加volatile
,让它每次用a的值都去内存中取,保证a值得内存可见性。
const_cast最常用的用途就是删除变量的const属性,简单明了,不用考虑太多。
dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)。在多态中,我们知道,子类对象、指针、引用都可以用父类对象或者指针去接收,这由语法自动完成切片。不太懂的可以看看这里。https://blog.csdn.net/Vickers_xiaowei/article/details/82750286#_98
向上转型:子类对象指针->父类指针/引用(不需要转换,自动完成切片)
向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)
#include
using namespace std;
class Person{
protected:
string _name;
virtual void Print()
{
cout << "I am the father" << endl;
}
};
class Student :public Person
{
public:
int _num;
virtual void Print()
{
cout << "I am the son" << endl;
}
};
void Func(Person* p)
{
//父类对象指针->子类指针/引用
Student* sp = dynamic_cast<Student*>(p);//只允许子类对象指针转换
sp->Print();
}
int main()
{
Person p;
Student s;
//Func(&p);//使用dynamic_cast,不能将父类指针转换成子类指针,防止了越界行为
Func(&s);
system("pause");
return 0;
}
涉及多态的类型转换最好使用dynamic_cast,防止越界。
static_cast用于非多态类型的转换(静态转换) ,任何标准转换都可以用它,但它 不能用于两个不相关的类型进行转换。 这里所谓的相关类型和C语言中可以隐式转换的相近类型概念基本一样,C++使用static_cast更加明显,增强了可读性。
#include
using namespace std;
int main()
{
int a = 10;
int*p = static_cast<int*>(&a);
*p = 20;
cout << a << endl;
system("pause");
return 0;
}
reinterpret_cast操作符用于将一种类型转换为另一种不同的类型。与C语言的强制转换可读性更好。
#include
#include
using namespace std;
int main()
{
int a = 10;
int*p = &a;
int b = reinterpret_cast<int>(p);
system("pause");
return 0;
}
少用类型转换,多使用C++标准的强制转换
对于单参数构造函数会将单参数隐式类型转换。
#include
using namespace std;
class A
{
public:
A(int a)
{
cout << "A(int a)" << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << endl;
}
private:
int _a;
};
int main()
{
A a1(1);
// 隐式转换-> A tmp(1); A a2(tmp);
A a2 = 1;
system("pause");
}
上述代码将int类型隐式转换成了自定义类型A,如果不想让这样的隐式类型转换,对于单参数类型转换,explicit关键字阻止经过转换构造函数进行的隐式转换的发生。
#include
using namespace std;
int main()
{
size_t pos = 0;
int end= 3;
while (end >= pos)
--end;
system("pause");
return 0;
}
int类型的end与size_t类型的pos在比较时候,会将end的int类型提升到size_t,类型提升总是提升到范围大的那一个,所以上面无符号的-1比0大,上面代码会陷入死循环。