《Effective C++》条款27

尽量少做转型动作

cpp 复制代码
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成分的更改倒是落实了。

所以请这么写:

cpp 复制代码
class B :public A
{
public:
	B(int x) :b(x),A(x) {};
	virtual void add()
	{
		A::add();
		b++;
	}

private:
	int b;
};

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

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

cpp 复制代码
class B :public A
{
public:
	...
	void func();
	...
};

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

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

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

cpp 复制代码
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。

相关推荐
王老师青少年编程2 小时前
csp信奥赛C++高频考点专项训练之字符串 --【字符串排序】:合并序列
c++·字符串·csp·高频考点·信奥赛·字符串排序·合并序列
handler013 小时前
UDP协议与网络通信知识点
c语言·网络·c++·笔记·网络协议·udp
神仙别闹3 小时前
基于QT(C++)实现学生成绩管理系统
数据库·c++·qt
君义_noip4 小时前
CSP-S 2025 入门级 第一轮(初赛) 完善程序(1)
c++·算法·信息学奥赛·初赛·csp 第一轮
蜡笔小马6 小时前
07.C++设计模式-组合模式
c++·设计模式·组合模式
liulilittle6 小时前
TCP UCP v1.0:BBR 的非破坏性约束层
网络·c++·网络协议·tcp/ip·算法·c·通信
每天回答3个问题6 小时前
leetcodeHot100 | 104.二叉树的最大深度
c++·面试·
坚果派·白晓明6 小时前
【鸿蒙PC三方库移植适配框架解读系列】第五篇:完整流程图与角色职责
c语言·c++·华为·harmonyos·鸿蒙
xiao_li_ya7 小时前
C++学习日记1(`*`的理解、const关键词)
开发语言·c++
郝学胜-神的一滴9 小时前
Qt 入门 01-02: 开发环境搭建指南
开发语言·c++·qt·客户端