条款5:对定制的“类型转换函数”保持警觉

ConnectionResetError 10054 根因分析与全链路防御指南 ConnectionResetError(错误码10054)是TCP协议中服务端主动发送RST包导致的强制断连,本质并非网络连接失败,而是服务端基于空闲超时、连接满载、TLS协商失败等策略做出的确定性终止决策。理解其底层原理有助于跳出‘重试’误区,转向连接生命周期管理。该错误高频出现在HTTP长连接、WebSocket、第三方API对接等场景,尤其在Nginx反向代理、负载均衡器(如AWS ALB)、WAF设备及内核conntrack机制下极易触发。本文结合Wireshark抓包分析、客户端心跳保鲜、协议指 阅读详情

什么是类型转换函数?
1)转换构造函数可以将一个指定类型的数据转换为类的对象
2)类型转换函数的作用是将一个类的对象转换成另一类型的数据
3)一个类中同时有转换构造函数和类型转换函数将产生二义性,程序报错

举一个复数的例子就明白了:

class Complex
{
public:
   Complex( ){real=0;imag=0;}
   Complex(double r,double i){real=r;imag=i;}
   operator double( ) {return real;} //类型转换函数
private:
   double real;
   double imag;
};

int main( )
{ 
   Complex c(3,4));
   double d;
   d=2.5+c;//要求将一个double数据与Complex类数据相加
   cout<<d<<endl;
   return 0;
}

当缺乏类型转换函数时,d=2.5+c就会报错。因为d是double类型,而c是一个Complex类。而自定义类型转换函数之后,上述main函数将会隐式调用operator double( ),将Complex类对象转换为double型数据。

那么现在解释条款5,为什么最好不要提供任何类型转换函数。
根本问题在于,在你从未打算也未预期的情况下,此类函数可能会被调用,而其结果可能是不正确、不直观的程序行为,很难调试。

看下面这一段代码:

class Rational
{
public:
    Rational(double a=0,double b=1){
        numerator=a;
        denominator=b;
    }
    operator double( ){
        return numerator/denominator;
    } //类型转换函数
private:
   double numerator;
   double denominator;
};

int main( )
{ 
   Rational r(1,2);
   cout<<r<<endl;
   return 0;
}

这段代码的Rational类里,我们忘了为它写一个operator<<,然而却在main函数里调用了<<,或许你会认为上述打印不会成功。但是你错了,编译器面对上述动作,发现不存在任何operator<<可以接受一个Rational,但它会想尽各种办法(包括找出一系列可接受的隐式类型转换)让函数调用动作成功。这虽然不至于造成灾难,却显示了隐式类型转换操作符的缺点:它们的出现可能导致错误(非预期)的函数被调用。

解决办法就是以功能对等的另一个函数取代类型转换操作符。
上述代码的类型转换函数可改成:

double asDouble() const;

如此的member function也因此必须被明确调用:

cout<<r;    //错误!Rational没有operator<<
cout<<r.asDouble(); //可以!以double的形式输出r

大部分时候,“必须明白调用类型转换函数”虽然带来些许不便,却可因为“不再默默调用那些其实并不打算调用的函数”而获得弥补。

通过单自变量constructor完成的隐式转换,较难消除。此外,这些函数造成的问题在许多方面比隐式类型转换操作符的情况更不好对付。

举个例子,考虑一个针对数组结构而写的class template:

template<class T>
class Array
{
    public:
        Array(int lowBound,int highBound);  //身为一个双自变量constructor,没有资格成为类型转换函数 
        Array(int size);    //可以用来作为一个类型转换函数 
        T& operator[](int index);
};

例如,考虑一个用来比较Array对象进行比较动作的函数,以及一小段代码:

bool operator==(const Array<int>& lhs,const Array<int>& rhs);
int main()
{
    Array<int> a(10);
    Array<int> b(10);
    for(int i=0;i<10;++i)
    {
        if(a==b[i]) //哎哟!"a"应该是 "a[i]"才对 
        {
            //do sth.
        }
        else
        {
            //do sth. else
        }
    }
    return 0;
}

我希望编译器发挥挑错功能,将a(实际上应该为a[i])挑出来,但它却没有报错。因为它看到的是一个operator==函数被调用,夹带着类型为Array< int >的自变量和类型为int的自变量b[i]。
虽然没有这样的operator==可以被调用,但编译器注意到,只要调用Array< int > constructor(需要一个int作为自变量),它就可以将int转为Array< int > object。
于是,循环的每一次迭代都拿a的内容和一个大小为b[i]的临时数组(其内容想必未定义)做比较。这种行为不仅不令人满意,而且每走过这个循环,我们都必须产生和销毁一个临时的Array< int > object。

而我们可能真的需要提供一个单自变量的constructor给我们的客户使用。
如何阻止编译器不分青红皂白地调用这样的constructor?关键词explicit。
这个特性之所以被导入,就是为了解决隐式类型转换带来的问题,只要将constructor声明为explicit,编译器便不能因隐式类型转换的需要而调用它们。不过显示类型转换仍是允许的。

如果编译器尚不支持关键词explicit,那么就只能通过以下做法阻止单变量constructor成为隐式类型转换函数:

template<class T>
class Array
{
    public:
        class ArraySize //这个class是新加入的
        {
            public:
                ArraySize(int numElements): theSize(numElements){}
                int size() const{
                    return theSize;
                }
            private:
                int theSize;
        };
        Array(int lowBound,int highBound);
        Array(ArraySize size);  //注意这个新的声明 
};

以一个int自变量构造起一个Array对象这个事实仍然可靠有效,而再次考虑上述main函数的代码,“if(a == b[i]) …”如今形成了一个错误。因为那将调用两个用户定制转换行为,一个将int转换为ArraySize,另一个将ArraySize转换为Array。如此的转换程序是禁止的。

类似ArraySize这样的classes,往往被称为proxy classes,它的每一个对象都是为了其他对象而存在的。proxy objects让你得以超越外观形式,进而控制你的软件行为,是一项很值得学习的技术。

所以不要提供转换函数,除非你确定需要它们。

ENVI基于Landsat影像构建郑州市2000-2019年遥感生态指数RSEI 本文基于landsat5、landsat7、landsat8三种传感器的影像,使用ENVI软件构建郑州市2000-2019年遥感生态指数RSEI。内含ENVI详细操作、使用的公式以及构建结果。 阅读详情

相关推荐

使用FloodRisk2插件进行洪水风险评估

入汛以来,长江流域持续的强降雨使得沿岸多地成为洪水风险极高地区,抗洪、抢险、救灾继新冠病毒之后成为又一个攻坚阵地。如何科学地评估洪水风险,是快速决策的关键。 实际生活中,根据风险是否可控,一般将洪水风险大致分为两类:一类是通过数据分析可以得出其发生的可能性和后果,如强降雨引发的区域性洪水、水库/大坝溃决洪水等。这类洪水可以通过有关资料分析和设定一定条件计算得到可能的损失后果,也就是说,风险可以预判。另一类洪水风险基本是未知的,如滑坡堵塞河道形成堰塞湖引发的洪水,无法预知事件发生的地点和规模,具体的洪水风险无

QGISClass的博客 2879

对定制的“类型转换函数”保持警觉

单自变量constructors是指能够以单一自变量成功调用的constructors。如此的constructors可能声明拥有单一参数,也可能声明拥有多个参数,除第一个参数之外都有默认值。 class Name { Name(const string& s)//可以把string转换为Name .... } class Rational { Rational(int num

707

python 爬虫 xpath 存储到数据库

参考

我是张先生 1289

More Effective C++(条款5:对定制的“类型转换函数”保持警觉)

1、C++ 允许内置数据类型之间(例如char和int,int和double等)进行隐式转换,对于内置类型之间的隐式转换有详细的规则,但不管怎样,这些都是语言提供的,既相对安全,我们又无法更改(也就是说,这些我们不用管也管不着);2、对于自定义的类类型,单自变量constructor(有单一参数或有多个参数且除第一个参数外都有默认值)和隐式类型转换操作符(operator之后加上一个类型名称,不能...

Unique-You的博客 315

互联网的发展简史—web

互联网是我现在生活所离不开的一个东西,但是你知道互联网的前世今生吗?本文将讲解互联网的发展史,以及很火的元宇宙概念。

yj11290301的博客 3562

基于Jeecgboot3.8.1的vue3版本前后端分离的flowable流程管理平台

基于Jeecgboot3.8.1的vue3版本前后端分离的flowable流程管理平台

宁波阿成的博客 1544

MEC | 条款5 对定制的“类型转换函数”保持警觉

能够以单一自变量成功调用的 constructors如此 constructors 可能声明拥有单一参数,也可能声明拥有多个参数,并且除了第1个参数之外都有默认值class Namepublic:// 可以把 string 转换为 Name...public:// 可以把 int 转换为 Rational隐式类型转换操作符 :是一个 member function,关键词 operator 之后加上1个类型名称。因为已经有了类型名称,因此不能为此函数指定返回值类型。public:...

RandyOliver's House 182

JAVA:Spring Boot 集成 Forest 优雅的 HTTP 客户端

Forest是一个优雅的Java HTTP客户端框架,通过注解式声明简化HTTP接口调用。它支持多HTTP客户端、自动参数绑定、序列化、重试机制和拦截器等功能。本文演示了如何在Spring Boot中集成Forest,包括配置、接口定义和调用示例,还展示了POST请求、文件上传等常见场景。相比传统HTTP客户端,Forest具有声明简洁、功能完善的特点,特别适合微服务调用和第三方API对接,能显著提升开发效率和代码可维护性。

木头 427

【More Effective C++ 条款5】对定制的“类型转换函数”保持警觉

1)C++允许内置数据类型之间进行隐式转换,比如char转int,int转double,对于内置数据类型的转换有详细的规则,但不管怎么样,这些都是语言提供的,相对安全,而且我们无法更改对于自定义类的类型,其隐式类型可以通过带单一自变量的构造函数和隐式类型转换操作符来实现2)单一自变量构造函数:指能够以单一自变量成功调用的构造函数,该构造函数可能只有一个参数,也可能有多个参数,并且除了第一...

Y先森0.0 301

【GlobalMapper精品教程】027:路径剖面和和视线工具的使用

路径剖面视线工具允许您使用加载的高程数据集沿用户指定的路径获取垂直剖面。要定义生成3D路径剖面所遵循的路径,只需单击鼠标左键选择路径的点,然后石键单击以结束路径。出现一个带有剖面的对话框,允许您设置视线分析或优化端点。

智慧空间实验室 2049

【第1章】基于FPGA的图像形态学处理学习教程——目录

本课程介绍图像形态学处理技术,通过腐蚀、膨胀、开运算、闭运算等算子对图像进行优化。腐蚀可去除边缘杂色使线条更清晰,膨胀能填补缺口修复图像,开运算擅长去噪,闭运算则用于修补断裂。课程内容涵盖四大形态学处理的理论分析、MATLAB仿真和FPGA开发实现,包括腐蚀、膨胀、开闭运算以及顶帽变换等操作,最后探讨形态学处理的实际应用场景。通过仿真测试和FPGA开发实践,帮助学员掌握图像"美容塑型"的核心技术。

MATLAB,verilog,python,opencv,tensorflow,caffe,C,C++ 338

More Effective C++ 条款5 对定制的"类型转换函数"保持警觉

1. C++ 允许内置数据类型之间(例如char和int,int和double等)进行隐式转换,对于内置类型之间的隐式转换有详细的规则,但不管怎样,这些都是语言提供的,既相对安全,我们又无法更改。 对于自定义的类类型,隐式转换可以通过带单一自变量的构造函数和隐式类型转换操作符来实现(所谓"单一自变量指的是可以有多个参数,但除了第一个参数其他参数必须有默认实参) 2. 对于自定...

ddzai7557的博客 154

ZYNQ BRAM实现PS与PL数据交互

有时CPU需要与PL进行小批量的数据交换,可以通过BRAM模块,也就是Block RAM实现此要求。本章通过Zynq的GP Master接口读写PL端的BRAM,实现与PL的交互。在本实验中加入了自定义的FPGA程序,并利用AXI4总线进行配置,通知其何时读写BRAM。以下为本实验原理图,CPU通过AXI BRAM Controller读取BRAM数据,CPU仅配置自定义的PL BRAM Controller 的寄存器,不通过它读写数据。

baidu_34971492的博客 2276

More Effective C++ 条款05:对定制的类型转换函数保持警觉

C++的类型转换,两种函数允许编译器执行这样的操作:单参数构造和隐式类型转换操作符。 单参数构造指可能声明单一参数,有可能拥有多个参数,并且除了第一参数之外都有默认值: class Name { public: Name(const string& s); //可以把string转换为name ... }; class Rational { public: Rational(int numerator = 0, int denominator = 1); //可以把

Stay hungry, Stay foolish 753

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

《More Effective C++》总结笔记(一)——基础议题、操作符

基础议题 条款1:仔细区别pointers和references 首先你必须认知一点,没有所谓的 null reference。 由于reference一定得代表某个对象,C++因此要求references必须有初值。 Pointers和references之间的另一个重要差异就是,pointers可以被重新赋值,指向另一个对象,reference却总是指向(代表)它最初获得的那个对象。 结论:当你知道你需要指向某个东西,而且绝不会改变指向其他东西,或是当你实现一个操作符而其语法需求无法由pointers

吴尼玛cs 291

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Effective C++ 学习笔记

条款1.pointer和reference:当需要指向某个东西,而且绝不会改变指向其他东西或实现一个操作符而其语法需求无法由pointers达成,你就应该选择references,任何其他时候,请采用pointers 条款2.最好使用c++转型操作符:static_cast ,const_cast,dynamic_cast(继承体系向下安全转换),  reinterpret_cast(转换函数指

SwenV5的专栏 640

操作符(条款5-8)

more effective C++ 操作符

lichao_n的博客 122

more effictive C++

条款1 仔细区别指针和引用 引用和指针的不同点 引用在定义时必须初始化,指针没有要求 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体 没有NULL引用,但是有NULL指针 sizeof的含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小 有多级指针,但没有多级引用 ...

weixin_43718250的博客 405

More Effective C++ (1)

简单分析总结了more effective c++ 的前十个条款: 剩下的条款to be continue~ 1.仔细区分指针和引用引用必须不能指向空,指针可以指向空,指针初始化是记得赋空值,重载某些操作符时(例如[])应该返回引用。 2.最好使用C++转型操作符旧式的C转型应该少用,尽量使用新的C++的转型static_cast<type> (expression)基...

aoan1126的博客 109

More Effective C++ 35 条款

一、基础议题(basics) 条款1:仔细区别 pointers 和 references(Distinguish between pointers and references) 一个基本的语法问题。 条款2:最好使用 C++ 类型转换运算符(Prefer C++-style casts) C++的类型转换运算符安全,容易解析,分工精细,虽然要打多点字。 条款3:绝对不要以 polym...

weixin_30907935的博客 185

《More Effictive C++》学习笔记 — 基础议题 操作符 异常

这里写目录标题条款3 — 绝对不要以多态方式处理数组1、C++标准中的规定2、编译器实现3、问题分析 条款3 — 绝对不要以多态方式处理数组 好吧,这个问题在《深度探索C++对象模型》也提到了。当时,我只在msvc上验证了下,发现并不是这样。现在又看到这个提议,我认真地研究了下。 1、C++标准中的规定 首先,我们来看看C++中是怎样规定的(摘自C++20草案): In an array delete expression, if the dynamic type of the object to be

coding-hwz 671

More Effective C++之操作符operators

可加以重加载的操作符overloadable operators,它让我们所定义的类型有着和C++内建类型一样的语法,允许我们在“操作符背后的支撑函数”内放置威力强大的手段,那是内建类型不可能有的待遇。当然,“可让诸如‘+’和‘==’符号做任何事情”这个事实,也意味着我们可能利用重载操作符写出一些令人难以理解的程序。成熟的C++程序员知道如何驾驭操作符重载的强大威力,不落入令人费解的沉沦中。可叹的是,稍有不慎,便向下沉沦。

chnming1987的博客 1212

more effective c++读书笔记 第二章 操作符

条款5 对定制的类型转换函数保持警觉 在class中可定制两种类型转换函数,一个是单自变量的构造函数(如果带默认参数,可以有多个变量),二是operator 类操作符的重载,这里的内容较基础。对于单自变量构造函数,现在可以用explicit 关键字,要求显示构造,即可避免默认的转换行为,对于不支持explicit的编译器,作者提供了一种做法 class Array { public: class ArraySize { public: ArraySize(int s) : size(s) {}

m0_52329237的博客 244

《More Effective C++》阅读笔记

在读完《C专家编程》之后收获良多就选择了继续读一些相关的书籍,本打算先看《算法导论》的,但是《算法导论》但是算法导论的篇幅实在太多,无意中在图书馆中发现了这本书就开始阅读,写下这边文档供以后回顾。 文中代码调试编译执行平台为window7,vs2013 文章目录条款一:仔细区分pointers和references总结条款二:最好使用C++转型操作符1. static_cast&lt;&g...

梦的灰色边沿... 675

《More Effective C++》 笔记

条款1: 仔细区分 pointers 和 references pointers 是一个变量,其本身存放实际内容的地址 references 是一个引用,其就是实际内容的别名 两者都支持多态但是还是有一定区别的 pointer 在进行创建的时,不一定要立即给定一个准确值,虽然发生这种情况时,通常会赋予一个 null,来区别当前指针未进行初始化,杜绝由此产生的野指针,而 pointer 也是可以进行...

不积跬步无以至千里 435

More Effective C++ 学习笔记(2)

操作符 主旨:讨论“重载操作符”被调用的时机、方法、它们的行为,应如何与其它操作符产生关系,以及如何获取“重载操作符”的控制权 条款5:对定制的“类型转换函数”保持警觉 故名思意,就是在自己提供的类上编写某些函数以便为了编译器拿来作为隐式类型转换用时一定要多加注意,最好不要做这样的操作 两种函数可以做到上述点: 单自变量constructors 核心点:...

qq_20507961的博客 314
上一篇: 数据结构--图
下一篇: 条款6:区别increment/decrement操作符的前置和后置形式
Nim的辙迹
博客等级 码龄10年 17粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值