C++调用多态函数时的坑【隐式类型转换】

737 阅读3分钟

昨晚在写bug的过程中,发现了一个让人摸不着头脑的错误。先交代一下发生这个错误的背景:

1)定义了一个名为TCP_MSG_HEAD的宏,值为0xBBAA55AA,作为目标TCP数据包的报文头,

#define TCP_MSG_HEAD = 0XBBAA55AA;

2)调用socket的readAll()方法,返回一个字节数组,也就是当前socket接收缓冲区里字节流的所有内容,并追加到内存缓冲区。

QByteArray readArray=m_pServerTcpSocket->readAll();                                     
m_bufferData.recevData.append(readArray);         

3)调用indexOf(TCP_MSG_HEAD);,获取报文头在内存缓冲区中第一次出现的位置index。

int index=bufferData.recevData.indexOf(m_headerArray);        
cout<<index;  

然后奇怪的事情发生了:

在这里插入图片描述
显然,我要找的报文头在内存的0~3位,但是,index的值??
在这里插入图片描述
居然是1,而不是0。
在这里插入图片描述
最后破案了,罪魁祸首是 C++多态函数的调用+隐式类型转换 ,来看看QByteArray类型的indexOf()方法有多少个重载函数:
在这里插入图片描述
这三个重载函数的第一个参数都是待查找的目标,类型可以是char型、char型指针、QByteArray字节数组。

但是,如果传入的参数类型不属于上面的任何一个,会怎么样?

一般是会报错,比如我这里随便往indexOf()里面传了一个QTextEdit对象,会产生以下的错误信息,能报错还算是比较好办的,最怕的就是C++自动为我们进行了 隐式类型转换 !
在这里插入图片描述
这个隐式类型转换,有时候能够为我们提供便利,比如说在 if 条件判断语句中,可以自动把一些表达式转换成 bool 型,或者可以把char型字符数组自动转换成字符串string。有时候就很坑了,让你程序出错都不知道为啥,就比如文章开头我遇到的这种情况。

我们都知道 int 型和 char 型变量之间是可以进行转换的。比如:

int b = 66; 	//字母B的ASCII码  
cout<<(char)b;

控制台打印结果:
在这里插入图片描述
所以,当我调用indexOf(TCP_MSG_HEAD)时,相当于是调用了indexOf(0xBBAA55AA),程序找不到一个参数能与之匹配的indexOf()函数,它就很帮倒忙地为我们进行了隐式类型转换,把 unsigned int 型转换成 char 型,因此在调用这个函数的时候,程序没有报错。

但是,程序其实还是提醒过我的,只是我一直没有注意到这个警告:在这里插入图片描述
啥叫从 unsigned int 到 char 的截断呢?定义的宏常量在程序中被认为是 unsigned int 型的,它的范围比 char 型大,是4个字节,而 char 型变量只占一个字节:

cout<<sizeof(unsigned int);   
cout<<sizeof(char);           

在这里插入图片描述
所以,当C++自动为我们进行 unsigned int 到 char 的类型转换时,由于 char 型变量的范围小,发生了截断,所以只留下了0xBBAA55AA中的最后两个AA,也就是说,变成了我们要在字节数组中,寻找AA第一次出现的位置,返回的index就是1了。

为了防止C++自动进行隐式转换,可以在类的构造函数前加上 explicit 关键字。
参考:C++ explicit构造函数----禁止隐式格式转换

不过在这个demo中不适用,因为 unsigned int 和 char 都是基本数据类型,只能用别的办法解决了,比如将报文头先转换成QByteArray字节数组,再调用indexOf()方法,这样调用的就是参数为QByteArray的那一个重载函数,也就避免了发生隐式转换了~

P.S:如有错误,欢迎指正~