QT中使用C++的指针

发表于:2016-11-07 09:57

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:z少爷    来源:51Testing软件测试网采编

  之前没有接触过 c++,不过听说 c++ 的指针很坑,直到最近在用 QT / C++ 写一个 Linux Deepin 系统上检测网络流量和网速的小程序时,发现 c++ 的指针用起来真的特别蛋疼。
  不过好在花了几个小时最终还是明白了指针的用法。
  有一段代码的原型大概是这样的:
  QList<NetFlowObject>  netflowobj_list;
  /** 从 list 列表中找出网卡名为 ifname 的 NetFlowObject 对象 **/
  bool getNfoFromList(QString ifname, NetFlowObject &nfo);
  其中 NetFlowObject 是自己写的一个类,QList 是 Qt 提供的一个链表。 getNfoFromList 函数返回 boolean 型结果,如果找到相同名称的网卡,返回 true,并将 nfo 设为 QList 中找到的 NetFlowObject 对象。否则返回 false。
  那么最开始的想法是通过遍历 QList 找到 NetFlowObject 对象。
bool NetInfo::getNfoFromList(QString ifname,NetFlowObject &nfo) {    //-------- A① foreach(NetFlowObject o, netflowobj_list) {              //-------- A② if(o.getIfName() == ifname) {  //-------- A③ nfo = o; return true; } } return false; }
void NetInfo::someFunction() {
// 如果找到相同的 nfo 对象,修改它的数据
NetFlowObject nfo1;
bool finded = getNfoFromList(ifname, nfo1);              //-------- B①
if(finded) {
nfo1.updateRecvBytes(if_recv_bytes.toInt());
nfo1.updateTransBytes(if_trans_bytes.toInt());
}
}
  嗯,上面的这段代码很显然没有办法修改 QList 链表中的对象的属性。首先,函数是传值的,也就是说 A① 处函数的参数 nfo 是不会影响 someFunction 里 B① 处的 nfo1 对象的。nfo1 对象的属性改变同样也不会影响 nfo 对象。
  通过函数的参数传递的只是 nfo1 对象的一个副本,两个对象之间不会影响。
  其次,A②处的 foreach 这个便捷的循环也是提供 QList 对象的一个副本,这样的话,更加没有办法修改找到的 NetFlowObject 对象了。
  好吧,这个错误是 c++ 最常见也是最愚蠢的错误,那么想要得到 QList 中的某个 NetFlowObject 对象的引用,函数传递的就不能是 NetFlowObject 对象了,那么就改成 NetFlowObject * 也就是指针吧。另外,将循环改为 for 计数循环。
  代码如下
bool NetInfo::getNfoFromList(QString ifname,NetFlowObject *nfo) {
for(int i = 0; i < netflowobj_list.count(); i++) {
NetFlowObject o = netflowobj_list[i];
//        PrintUtil::print(o.getIfName() + "  ===  " + QString::number(o.getLatestRecvBytes()));
if(o.getIfName() == ifname) {
*nfo = netflowobj_list[i];  // 将指针所指向的 NetFlowObject 对象修改为 o      -------C①
return true;
}
}
return false;
}
  相应的,
  bool finded = getNfoFromList(ifname, &nfo1);
  但是这样做,发现修改 nfo1 对象仍然没有效果, QList 中 NetFlowObject 对象的属性依然没有改变。恩没有错,上面代码 C① 处又是传递的副本。
  这里要说一下 QList 对象的 at(i) 函数和 QList[i] 数组形式得到的对象是不同的。函数原型为 const T &QList.at(int i) const,也就是不能通过 at() 的返回值对 nfo 对象进行修改,
  而数组形式的函数原型是 T &QList::operator[] (int i),也就是用起来和平常的数组没什么太大区别。
  既然一层引用不能达到效果,那么,函数传递的时候,就传一个 NetFlowObject * 对象的指针,也就是作为 NetFlowObject 对象的指针的引用。(这个指针的指针说起来太绕口了,第二个指针改称引用,不然脑子就浆糊了),贴出最终的代码:
bool NetInfo::getNfoFromList(QString ifname,NetFlowObject **nfo) {
for(int i = 0; i < netflowobj_list.count(); i++) {
NetFlowObject o = netflowobj_list[i];
//        PrintUtil::print(o.getIfName() + "  ===  " + QString::number(o.getLatestRecvBytes()));
if(o.getIfName() == ifname) {
*nfo = &netflowobj_list[i];  // 将指针所指向的 NetFlowObject 指针修改为 QList 中第 i 个对象的引用
return true;
}
}
return false;
}
void NetInfo::someFunction() {
NetFlowObject *nfo;
bool finded = getNfoFromList(ifname, &nfo);
if(finded) {
nfo->updateRecvBytes(if_recv_bytes.toInt());
nfo->updateTransBytes(if_trans_bytes.toInt());
}
}
  通过两层引用,最终达到了修改 QList 链表中对象的目的。
  感觉还有一种解决方法,就是将函数原型 getNfoFromList 修改成 NetFlowObject * getNfroFromList(QString ifname);
  找到相应的对象后直接返回该对象的引用,这样就不用通过函数参数传递两层引用了。
  --------------------------  思考 -------------------------
  引用指针绕的头都晕了,而且这个错误理论上应该属于逻辑错误(编译时不会报错,运行时不会发生异常),但是特喵的就是结果不对,debug 起来也很蛋疼,通过长时间的分析和总结才能得到正确的结果。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号