注册个人网站要多少钱,新竹自助网站,网络哪个运营商好,重庆百度推广电话目录 写在前面
类型转换的方法
static_cast
reinterpret_cast
dynamic_cast
const_cast
关于类型转换的使用建议
致谢#xff1a; 写在前面
鸽了好多天了#xff0c;这几天惰性使然博主休息了一下。磨刀不误砍柴工#xff0c;这几天会逐渐赶上之前的学习进度。今天带…目录 写在前面
类型转换的方法
static_cast
reinterpret_cast
dynamic_cast
const_cast
关于类型转换的使用建议
致谢 写在前面
鸽了好多天了这几天惰性使然博主休息了一下。磨刀不误砍柴工这几天会逐渐赶上之前的学习进度。今天带来的是cpp11风格类型转换的使用方法对于各种使用方法给出了相应的测试代码。总体来说应该是覆盖了cpp中的重点强制转换的使用场景。对于cpp风格转换的使用当然是值得鼓励的但是也要避免这类操作的滥用在执行操作之前一定要清楚自己的行为。接下来就同博主一起练习一下吧。 类型转换的方法 c风格的强制类型转换 type var1 (type) var; eg:int a (int) b; cpp新标准的强制类型转换 type var1 type_operatortype (var); type_operator static_cast|| reinterpret_cast|| const_cast || dynamic_cast
static_cast static_cast 用于静态类型转换比较温和的转换例如int char 主要用法 对于基本类型中可能会发生数据的丢失问题如double int这种情况需要开发人员对自己的操作有着深刻的理解。 用于类层次结构中基类和派生类之间指针或者引用的转换。 在类层次结构转换中从派生类到基类的转换是安全的而反方向可能不安全。 static_cast方法可以吧空指针转换成任意类型的空指针。 也可以把任意类型的表达式转换成void类型。 下面依次对以上用法进行举例说明基本都可以运行成功有问题的部分均会解释 基本类型转换 #include iostreamvoid test01(){//convert the basic typeint src 888;char tag static_castchar (src);} 有继承关系的类型转换首先定义三个类基类Animal是一个纯虚基类虚基类不可实例化但是可以通过强转转化对象比如多态的实现其实就是基类的一种隐式转换内含一个纯虚函数cryDog 和 Cat是两个派生类分别重写这个方法下面是这三个类的定义 #include iostreamclass Animal{public:virtual void cry() 0;};class Cat:public Animal{public:void cry(){std::cout meow meow meow~~~ std::endl;}};class Dog:public Animal{public:void cry() override{std::cout woof woof woof~~~ std::endl;}}; 首先是指针类型变量的强制转换派生类转换成基类是安全的但是基类转换成派生类可能不安全尤其是多个派生类。 比如当一个Dog* 的对象被转换成Animal*这是安全的但是反向转回有可能会有Dog* - Animal* - Cat*。这样就会导致未定义行为且这种行为不会被编译器察觉因此这种转换应当被避免。 void test02(){//type of pointerAnimal* dog1 new Dog();// Animal* dog2 static_castAnimal* (dog1);//using auto to avoid the duplicate declarationauto* dog2 static_castAnimal* (dog1); //derived to base//auto* dog3 static_castDog* (dog2); //base to derived, reversely(downcast is dangerous)auto* cat static_castCat* (dog2); //reason for danger, this may not be detected by the compiler!} 其次是引用类型的强制转换一样的原理依旧不推荐进行基类到派生类的强制转换。 但是这里注意一件事在默认构造实例化一个对象时Dog dog1();这种定义方法会造成类对象实例化和函数声明的歧义问题。Dog dog1; 和 Dog dog{};这种定义方法是可以的。 void test03(){// Dog dog1{}; //allowed// Dog dog1(); //not allowed, ambiguous error occurrence//since it can be explained as both function declaration and class instantiationDog dog1; //allowedAnimal a static_castAnimal (dog1);// Animal a();//instantiation is not allowed in pure virtual base class,//using type conversion can be fine} 最后是关于NULL 和 void*类型的转换即将nullptr或者 NULL转换成任意类型或者将任意类型转换成void* 类型都是可以的。 void test04(){//convert nullptr to any type of pointerint* pInt static_castint* (nullptr);double* pDouble static_castdouble * (nullptr);Dog* pDog static_castDog * (nullptr);//convert any type into a void typeint* a new int(10);void* v static_castvoid* (a);int* my_array new int[10];void* va static_castvoid* (my_array);} 最后出去注释的部分运行全部成功。
reinterpret_cast 一种非常低级别的强制类型转换方法可以实现数值和指针的转换以及不同类型之间的转换。 滥用很可能造成风险除非是对于此操作完全理解或者是操作本身就是底层低级别。 如果可以使用static_cast就尽量不要使用reinterpret_cast 下面分别对整形转换成指针类型 指针类型的强制转换以及引用类型的强制转换进行代码测试。 其中test06(), test07()输出应当一致而test05()没有输出 void test05(){//converting one number to one pointerint nu 0x666666;int* pnu reinterpret_castint* (nu);}void test06(){//converting between different type of pointer//Dog* dog; //initialization for one pointer pointing at nullptrstd::cout --------------test for the pointer-------------- std::endl;Dog* dog new Dog;auto* ar reinterpret_castAnimal* (dog);auto* as static_castAnimal* (dog); //if possible, using the static_cast is preferablear-cry();as-cry();}void test07(){//converting between different type of referencestd::cout --------------test for the reference-------------- std::endl;Dog dog;auto ar reinterpret_castAnimal (dog);auto as static_castAnimal (dog); //if possible, using the static_cast is preferablear.cry();as.cry();} 最终输出如下所示此处类型强转成功 /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug/project01--------------test for the pointer--------------woof woof woof~~~woof woof woof~~~--------------test for the reference--------------woof woof woof~~~woof woof woof~~~Process finished with exit code 0
dynamic_cast dynamic_cast即动态类型转换其最常见的用途是在安全地将基类指针或引用转换为派生类指针或引用。这种转换在运行时检查对象的实际类型以确保转换是有效的。 当转换类型为指针根据基类指针是否指向继承类指针来相应地进行处理如果转换失败会返回一个空指针成功则返回一个正常转换成功的对象指针。 当转换类型为引用如果转换失败会抛出一个异常bad_cast。 因为有检查过程dynamic_cast的运行速率要慢于static_cast和reinterpret_cast。 注意dynamic_cast 将父类转换成子类时基类中必须至少有一个虚函数。如果没有则无法支持运行时类型信息RTTIRun-Time Type Information此时会导致编译错误。 现在开始进行代码测试部分我们设定两个测试函数分别测试指针和引用的参数传入。 首先我们创建一个新的方法play()来辅助测试并在基类中添加纯虚函数更新后的类定义如下所示 #include iostreamclass Animal{public:virtual void cry() 0;virtual void play() 0;};class Cat:public Animal{public:void cry() override{std::cout meow meow meow~~~ std::endl;}void play() override{std::cout climbing the tree for fun~~~ std::endl;}};class Dog:public Animal{public:void cry() override{std::cout woof woof woof~~~ std::endl;}void play() override{std::cout catching the plates for fun~~~ std::endl;}}; 然后对于引用和指针类型的转换分别设计不同的判断类型 对于引用类型转换失败会抛出异常因此要进行异常处理。 对于指针类型转换失败会返回一个空指针因此仅对于返回值进行判断即可判断其类型。 测试函数的代码如下所示 void AnimalPlay(Animal item){item.cry();try{Dog dog dynamic_castDog (item);dog.play();}catch(std::bad_cast e){std::cout this is a cat std::endl;Cat cat dynamic_castCat (item);cat.play();}
}void AnimalPlay(Animal* pitem){pitem-cry();auto* pDog dynamic_castDog* (pitem);if(pDog){pDog-play();}else{std::cout this is a cat std::endl;auto* pCat dynamic_castCat* (pitem);pCat-play();}
} 为了配合上述上述函数进行测试一个测试函数被定义如下对于两种类型的指针和引用均进行了测试 void test08(){Dog* dog1 new Dog();Cat* cat1 new Cat();Animal* a1 dog1;Animal* a2 cat1;std::cout test for references std::endl;Dog dog2;Cat cat2;AnimalPlay(dog2);AnimalPlay(cat2);std::cout test for pointers std::endl;AnimalPlay(a1);AnimalPlay(a2);} 最终输出结果如下判断和异常处理均成功。 /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug/project01
test for references
woof woof woof~~~
catching the plates for fun~~~
meow meow meow~~~
this is a cat
climbing the tree for fun~~~
test for pointers
woof woof woof~~~
catching the plates for fun~~~
meow meow meow~~~
this is a cat
climbing the tree for fun~~~Process finished with exit code 0
const_cast 用于去除其const的属性但是仅适用于指针或者引用。 下面开始进行测试 对于常指针类型的测试对于常指针转换成指针类型static_castchar*以及reinterpret_castchar*均失效只有const_cast是有效的各位可以自行测试 下面是相关代码 void test_4_const_pointer(const char* p){//change the const type pointer into non-const and change the value//both are not allowed while const_cast is the only choice
// char* ptr static_castchar* (p);
// char* ptr reinterpret_castchar* (p);char* ptr const_castchar* (p);ptr[0] A;//directly change the objectconst_castchar* (p)[1] B;std::cout end of conversion function std::endl;std::cout p std::endl;
}void test09(){//test for const_cast//string arraychar p[] 12345678;std::cout before of conversion function std::endl;std::cout p std::endl;test_4_const_pointer(p);std::cout out of conversion function std::endl;std::cout p std::endl;
} 输出结果如下在进行转换后成功地对指针指向的内容进行了修改 /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug/project01
before of conversion function
12345678
end of conversion function
AB345678
out of conversion function
AB345678Process finished with exit code 0 接下来是对于传值转换的测试按照之前说的只可以转换引用或者指针可以遇见这种操作会引发编译错误 void test_4_const_value(const int p)
{int q p;const_castint(p) 888;// NO ! no conversion using const_cast converting a valuestd::cout p std::endl;
}void test10(){int a 10;test_4_const_value(a);std::cout a std::endl;
} 最终输出结果如下 [ Build | project01 | Debug ]
/home/herryao/Software/clion-2023.2/bin/cmake/linux/x64/bin/cmake --build /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug --target project01 -- -j 10
[ 50%] Building CXX object CMakeFiles/project01.dir/main.cpp.o
/media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/main.cpp: In function ‘void test_4_const_value(int)’:
/media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/main.cpp:181:5: error: invalid use of ‘const_cast’ with type ‘int’, which is not a pointer, reference, nor a pointer-to-data-member type181 | const_castint(p) 888;// NO ! no conversion using const_cast converting a value| ^~~~~~~~~~~~~~~~~~
gmake[3]: *** [CMakeFiles/project01.dir/build.make:76: CMakeFiles/project01.dir/main.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:83: CMakeFiles/project01.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:90: CMakeFiles/project01.dir/rule] Error 2
gmake: *** [Makefile:124: project01] Error 2 接下来是对传引用修改常量的测试其测试逻辑类似于传指针修改对象类型 void test_4_const_reference(const int p)
{int q p;const_castint(p) 888;std::cout end of conversion function std::endl;std::cout p std::endl;
}void test11(){int a 10;std::cout before of conversion function std::endl;std::cout a std::endl;test_4_const_reference(a);std::cout out of conversion function std::endl;std::cout a std::endl;
} 输出结果如下可以看出成功地对对象进行了修改。 /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug/project01
before of conversion function
10
end of conversion function
888
out of conversion function
888Process finished with exit code 0 最后一个是一个特例即不可以对常量字符串进行修改简单做一个测试依旧使用之前用到的常量指针类型的测试函数进行测试 void test_4_const_pointer(const char* p){//change the const type pointer into non-const and change the value//both are not allowed while const_cast is the only choice
// char* ptr static_castchar* (p);
// char* ptr reinterpret_castchar* (p);char* ptr const_castchar* (p);ptr[0] A;//directly change the objectconst_castchar* (p)[1] B;std::cout end of conversion function std::endl;std::cout p std::endl;
}void test12(){test_4_const_pointer(hello, world);
} 输出结果如下报了段错误这是由于常量字符串位于常量区这个位置的内容不支持修改 /media/herryao/81ca6f19-78c8-470d-b5a1-5f35b4678058/work_dir/Document/computer_science/QINIU/projects/week05/Mon/project01/cmake-build-debug/project01Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) 警告在进行常量修改时首先要清楚此处的内存是可修改的。
关于类型转换的使用建议 static_cast静态类型转换编译的时c编译器会做编译时的类型检查隐式转换基本类型转换父子类之间合理转换。 在c语言中可以隐式转换的情况一般都可以用static_cast进行替换。 若不同类型之间进行强制类型转换用reinterpret_cast 进行重新解释。 static_cast和reinterpret_cast 基本上把C语言中的 强制类型转换覆盖但值得注意的是reinterpret_cast很难保证移植性而且其级别很低滥用容易出错。 dynamic_cast动态类型转换安全的虚基类和子类之间转换运行时类型检查运行速度相比其他两种略慢值得注意的是dynamic_cast转换失败的处理方法大家可以多多联系保证熟练度。 const_cast取出变量的只读属性。 最后的忠告程序员必须清楚的知道: 要转的变量类型转换前是什么类型类型转换后是什么类型转换后有什么后果。 C大牛建议一般情况下不建议进行类型转换避免进行类型转换。
致谢 感谢各位的支持和坚持希望大家的cpp水平越来越强。 感谢Martin老师的课程。 抱歉之前的懒惰我会尽力在这段时间赶回进度大家共勉。