《More Effective C++》《基础议题——2、尽量使用C++类型的风格转换》

这篇具有很好参考价值的文章主要介绍了《More Effective C++》《基础议题——2、尽量使用C++类型的风格转换》。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、term2:尽量使用C++类型的风格转换

类型转换是一般程序员所不能忍受的,但是在紧要关头,类型转换是必须的。C风格的类型转换太过简单,粗暴,不能进行精确的类型转换;为了弥补C转换上功能的不足,C++提供了四种常用的类型转换来应付复杂的转换需求。

1.1 static_cast

static_cast用于在编译时执行类型转换,主要用于相对安全的类型转换,比如基本数据类型的转换,具有继承关系的指针或引用之间的转换。

1.1.1 基本数据类型转换

用于基本数据类型之间的隐式转换,这种情况下使用static_cast更为明确。举个栗子:

#include <iostream>

int main(){
	double myDouble = 3.14;
	int myInt = static_cast<int>(myDouble);
	std::cout <<"Double: "<<myDouble<< ", Int : "<<myInt <<std::endl;
	return 0;
}

在这个例子中。通过static_cast将double类型的变量转化为int类型的变量,使用static_cast一目了然。

1.1.2 指针类型转换

static_cast也可以用于在指针类型之间进行安全转换,避免一些问题,例如在基类和派生类之间进行转换。

#include <iostream>
using namespace std;
class Base{
public:
	virtual ~Base(){}
};
class Derived: public Base{
public:
	void derivedFunction(){
		cout << "Derived function."<<endl;
	}
}
int main(){
	Base* basePtr = new Derived;
	Derived* derivedPtr = static_cast<Derived*>(basePtr);
	derivedPtr->derivedFunction(); //安全地调用派生类函数
	delete basePtr;
	return 0;
}

程序运行输出:

Derived function.

在这个例子中,basePtr是一个指向基类的指针,通过static_cast将其转换为指向派生类对象的指针,从而可以安全地调用派生类函数。如果存在不安全的类型转换,可以考虑使用dynamic_cast进行运行时检查。

1.2 const_cast

const_cast用于类型转换掉表达式的const或者volatileness属性,他也仅仅只能改变一些东西的constness和volatileness属性,如果做这两个属性之外的转换,将会被编译器拒绝。
const_cast并没有真正去除复合类型中const和volatile属性。值得注意的是:变量本身的const属性是不能去除的,要想修改变量的值,一般是去除指针(或引用)的const属性,再进行间接修改。通过const_cast运算符,也只能将const type转换为type,将const type&转换为type&。也就是说源类型和目标类型除了const属性不同,其他地方完全相同。

1.2.1 去除const限定符

举个栗子:

class Widget{...};
class SpecialWidget:public Widget{...};
void update(SpecialWidget *psw);

SpecialWidget sw;  
//sw是一个非const对象
const SpecialWidget& csw = sw ;
//csw是sw的一个引用,它是一个const对象

update(&csw);
//error,不能将一个const SpecialWidget*变量传递给一个处理SpecialWidget*类型变量的函数

update(const_cast<SpecialWidget*>(&csw));
//true csw的const被显性转换掉,

update((SpecialWidget*)(&csw));
//同上,但是使用了C风格的类型转换


1.3 dynamic_cast

dynamic_cast,这种转换被用于安全地沿着继承关系向下进行类型转换,能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或兄弟类的指针或引用,并且能够知道转换是否成功,转换失败后会返回空指针或者抛出异常。
下面介绍dynamic_cast的使用场景:

1.3.1 在继承层次中进行安全的向下类型转换

当基类指针或引用指向派生类对象时,通过“dynamic_cast”进行向下类型转换,以确保类型的正确性。
举个栗子:

#include <iostream>
using namespace std;
class Base{
public:
	virtual ~Base(){}
};
class Derived: public Base{
public:
	void derivedFunction(){
		cout << "Derived function."<<endl;
	}
}
int main(){
	Base* basePtr = new Derived;

	if(Derived* derivedPtr = dynamic_cast<Derived*>(basePtr){
		//	安全地使用derivedPtr
		derivedPtr->derivedFunction();
	}else{
		//处理失败的情况
		cout << "error !" << endl;
	}
	return 0;
}

1.3.2 处理多态类型的情况

举个栗子:

#include<iostream>
using namespace std;
class Animal{
public:
	virtual void makeSound() const{
	cout << "Some generic sound." << endl;}
};
class Dog :public Animal{
public:
	void makeSound()const override{
	cout << "Woof Woof!"<<endl;
	}
};
class Cat:public Animal{
public:
	void makeSound()const override{
	cout << "Meow Meow!"<<endl;
	}
};
};
//Animal是基类,Dog,cat都是派生类,它们都重写了虚函数makesound
void animalSound(const Animal& animal){
	//使用dynamic_cast进行向下类型转换
	 if(const Dog* dog = dynamic_cast<const Dog*>(&animal)){
 		cout << "Dog says: ";
 		dog->makeSound();
	}else if(const Dog* dog = dynamic_cast<const Cat*>(&animal)){
 		cout << "Cat says: ";
 		cat->makeSound();
	}else{
		cout << "Unknown ainmal sound" <<endl;
	}
}
int main(){
	Dog myDog;
	Cat myCat;

	animalSound(myDog);
	animalSound(myCat);
	return 0;
}

输出内容:

Dog says: Woof Woof!
Cat says: Meow Meow!

...Program finished with exit code 0
Press ENTER to exit console.

在这个例子中,animalSound函数接受一个基类对象的引用,使用dynamic_cast将其向下类型转换为派生类对象,不同的类型调用不同的派生函数,这样可以在运行时动态确定对象的实际类型。

1.4 reinterpret_cast

reinterpret_cast是C++进行底层类型转换的一种强制类型转换。这种转换非常强大,也十分危险,因为他可以绕过类型系统,导致未定义的行为。下面介绍几个使用场景:

1.4.1指针类型之间的转换

#include<iostream>
using namespace std;
int main(){
	int value = 42;
	//将整数指针转换为字符指针
	char* charPtr = reinterpret_cast<char*>(&value);

	for(size_t i = 0;i < sizeof(int);i++){
		cout << "Byte " << i << static_cast<int>(charPtr[i]) << endl;	
	}
	return 0;
}

输出:

Byte 0 42
Byte 1 0
Byte 2 0
Byte 3 0

这个例子中,将一个整数指针转化为字符指针,然后通过字符指针输出整数在内存中的每一个字节;这样的转换通常用于底层的内存操作。

1.4.2整数和指针之间的转换

#include <iostream>
using namespace std;
int main(){
	int value = 42;
	//将整数转换为指针
	void* voidPtr = reinterpret_cast<void*>(value);
	
	//将指针再转为整数
	int* intPtr = reinterpret_cast<int*>(voidPtr);
	
	//输出转型后的整数数值
	cout << "Original:" << value <<", Back to int :" <<*intPtr  << endl;
	
	return 0;
}

在上述例子中,将一个整数转化为void* 指针,然后再转为整数指针;这种转换通常用于低级别的内存操作。

关于reinterpret_cast,转换函数指针的代码是不可移植的,所以在日常使用中应该避免转换函数指针类型,除非你身处险境,需要背水一战;不到万不得已,都不要使用。

2、总结

书山有路勤为径,学海无涯苦作舟。

3、参考

3.1 《More Effective C++》文章来源地址https://www.toymoban.com/news/detail-802711.html

到了这里,关于《More Effective C++》《基础议题——2、尽量使用C++类型的风格转换》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 什么是好的FPGA编码风格?(1)--尽量避免组合逻辑环路(Combinational Loops)

             组合逻辑环路 (Combinational Loops):指组合逻辑的输出信号 不经过任何时序逻辑电路 (FF等),而直接 反馈到输入节点 ,从而构成的电路环路。         此外,如果 直接将寄存器的输出端通过组合逻辑反馈到该寄存器的异步端口 (异步复位或异步置位),

    2024年02月05日
    浏览(32)
  • C++如何实现将一个整数转化为二进制数(使用尽量少的代码量)

    1、使用容器vector  这种方法非常简洁,当然使用数组也可以用不多的代码来进行实现。 将其转化为容易移植的函数如下: 注意在使用之前一定要#includevector头文件 2、一般数组实现 当然,还没有接触容器的小伙伴们也可以用普通的数组来进行实现,其算法仍然是通过对2取余

    2024年02月15日
    浏览(27)
  • java中实体pojo对于布尔类型属性命名尽量别以is开头,否则 fastjson可能会导致属性读取不到

    假如我们有一个场景,就是需要将一个对象以字符串的形式,也就是jsonString存到一个地方,比如mysql,或者redis的String结构。现在有一个实体,我们自己创建的,叫做CusPojo.java 有两个属性是布尔类型的,一个属性是有is开头,一个是没有is开头的,我们就可以做个对比。 现在

    2024年02月21日
    浏览(26)
  • 【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II

    视频算法专题 图论 割点 给定一个由 n 个节点组成的网络,用 n x n 个邻接矩阵 graph 表示。在节点网络中,只有当 graph[i][j] = 1 时,节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,

    2024年04月08日
    浏览(67)
  • Effective Java笔记(3)用私有构造器或者枚举类型强化 Singleton 属性

            Singleton 是指仅仅被实例化一次的类 。Singleton 通常被用来代表一个无状态的对象,如函数,或者那些本质上唯一的系统组件 。 使类成为 Singleton会使它的害户端测试变得十分困难 ,因为不可能给 Singleton 替换模拟实现,除非实现一个充当其类型的接口 。      

    2024年02月15日
    浏览(40)
  • 《Effective Java》第三条 用私有构造器或者枚举类型强化Singleton属性

    Singleton其实就是单例,即一个类在一个应用程序中只被实例化一次,只有一个对象。 本节讨论三种实现方式 私有构造+共有成员 私有构造+静态工厂方法+私有成员 枚举实现 1、共有成员 构造方法私有,有一个该类类型的公有不可变的实例域。 1.1 code 当类加载的时候就会创建

    2024年02月16日
    浏览(31)
  • 【Effective C++】让自己习惯C++

    C++由四个次语言组成: C:过程形式,没有模板、没有异常、没有重载 Object-Oriented C++:面向对象形式,类(构造函数和析构函数)、封装、继承、多态 Template:泛型编程、模板元编程 STL:容器、算法、迭代器和函数对象 目标是让编译器来替代预处理器,使用预处理器会存在

    2024年01月21日
    浏览(39)
  • effective c++ 笔记

    TODO:还没看太懂的篇章 item25 item35 模板相关内容 可以将C++视为以下4种次语言的结合体: C 面向对象 模板 STL 每个次语言都有自己的规范,因此当从其中一个切换到另一个时,一些习惯或守则是可能会发生变化的。 用const替换#define有以下2个原因: #define定义的符号名称可能没

    2024年02月10日
    浏览(21)
  • Effective C++ 条款四

    使用未初始化的值会导致不明确的行为 对于内置的数据类型(char,int,float,double等),在使用前必须进行初始化。 对于class来说,在使用对象之前,必须使用构造函数对成员变量进行初始化 但是需要注意赋值和初始化的区别 构造函数中的赋值操作(非初始化) 例如下面的构造函数

    2024年02月05日
    浏览(30)
  • effective c++ 条款2

    尽量用const,enum,inline替换#define 总结就是: 双const:指针不能变(只能指向这一块内存空间),指向的内存单元的值也不能变。 或者可以使用string常量代替: 类的静态成员 在头文件声明,在cpp文件中定义 这样也就完成了常量的定义。 可以在其他函数中,直接调用常量GamePl

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包