当前位置: 首页 > news >正文

《Effective C++》条款27

尽量少做转型动作

class A
{
public:A(int x) :a(x) {};virtual void add(){a++;}
private:int a;
};
class B :public A
{
public:B(int x) :b(x),A(x) {};virtual void add(){static_cast<A>(*this).add();b++;}private:int b;
};

如上描述把子类转型为A类,调用了A::add()。但是它调用的不是当前对象上的函数,而是稍早转型动作所建立的一个"*this对象之base class成分"的暂时副本上的add 。(成员函数只有一份,关键在于成员函数都有一个this指针,会因此影响成员函数操作的数据。)如果add修改了当前对象的内容,当前对象其实没有被改动,被改动的是副本。然而B类里面的add如果也修改对象,那么该对象会被改变。这使当前对象进入一种“伤残”状态:其base class成分的更改没有落实,而derived class成分的更改倒是落实了。

所以请这么写:

class B :public A
{
public:B(int x) :b(x),A(x) {};virtual void add(){A::add();b++;}private:int b;
};

如果想使用dynamic_cast,通常是你想在一个你认定为子类对象身上执行子类操作函数但是你手上只有一个指向基类的指针或引用。你只能靠它们来处理对象。有两个做法可以避免这个问题:

假设子类有一个唯一的函数func

class B :public A
{
public:...void func();...
};

你可以使用容器并在其中存储直接指向子类对象的指针:

typedef vector<shared_ptr<B>> Bptr;
Bptr bp;
...
for (Bptr::iterator iter = bp.begin();iter != bp.end();++iter)
{(*iter)->func();
}

而另一种做法可以让你通过基类接口处理“所有可能之各种A派生类”,那就是在基类内提供virtual函数做到你想对任何派生类做的事:

class A
{
public:virtual void func(){// 什么也不做,缺省}...
};
class B :public A
{
public:virtual void func(){...}...
};
int main()
{typedef vector<shared_ptr<A>> Aptr;Aptr ap;...for (Aptr::iterator iter = ap.begin();iter != ap.end();++iter){(*iter)->func();}
}

这两种做法都可以替代dynamic_cast。

 

相关文章:

  • python 生成器的作用
  • sql手工注入漏洞测试(MYSQL)-墨者-url信息
  • express+mySql实现用户注册、登录和身份认证
  • WEB渗透—反序列化(九)
  • golang 集成logrus日志框架
  • 基于SpringBoot的旅游网站的设计与实现
  • Could not resolve all files for configuration ‘:app:androidJdkImage‘.
  • Go语言使用AES加密解密
  • 漏洞复现--致远 M3 反序列化 mobile_portal RCE
  • 原生GPT本地及云端部署方式保姆级教程
  • 嵌入式硬件基础知识——1
  • 【LabVIEW学习】3.labview制作安装程序
  • Kafka 如何实现顺序消息
  • 力扣100. 相同的树
  • redis运维(十五) 集合
  • 3.7、@ResponseBody 和 @RestController
  • Angular2开发踩坑系列-生产环境编译
  • co.js - 让异步代码同步化
  • CSS居中完全指南——构建CSS居中决策树
  • ES6 ...操作符
  • GraphQL学习过程应该是这样的
  • Lucene解析 - 基本概念
  • Median of Two Sorted Arrays
  • MySQL数据库运维之数据恢复
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Node + FFmpeg 实现Canvas动画导出视频
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • React Transition Group -- Transition 组件
  • Redis 懒删除(lazy free)简史
  • 读懂package.json -- 依赖管理
  • 基于HAProxy的高性能缓存服务器nuster
  • 简析gRPC client 连接管理
  • 说说动画卡顿的解决方案
  • ​ubuntu下安装kvm虚拟机
  • #Z0458. 树的中心2
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)Nginx简介和安装教程
  • (SpringBoot)第二章:Spring创建和使用
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (过滤器)Filter和(监听器)listener
  • (一)u-boot-nand.bin的下载
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET Micro Framework初体验(二)
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .net6使用Sejil可视化日志
  • .Net各种迷惑命名解释
  • .NET性能优化(文摘)
  • /etc/sudoer文件配置简析
  • @Autowired 与@Resource的区别
  • [ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证