曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 2477|回复: 0
打印 上一主题 下一主题

向上/向下强制转换,向上/向下隐式转换

[复制链接]

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
跳转到指定楼层
楼主
发表于 2013-12-12 22:47:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一般情况下,C++ 不允许将一种类型的地址赋给另一种类型的指针,也不允许一种类型的引用指向另一种类型,比如:
  1. double x = 2.5;
  2. int *pi = &x;    //错误,指针类型不匹配
  3. long & r1 = x;   //错误,引用类型不匹配
复制代码
但是在语法上来说,通过强制类型转换不会发生编译错误,比如 int *pi = (int *)&x; 。

然而,指向基类的引用或指针可以引用派生类对象,而不必进行显式类型转换,比如:
  1. BrassPlus dilly ("Annie Dill", 493322, 2000);
  2. Brass *pb = &dilly;  // 正确
  3. Brass *rb = dilly;     // 正确
复制代码
将派生类引用或指针转换为基类引用或指针被称为向上强制转换(upcasting),这使得公有继承不需要进行显式类型转换。这个规则是 is-a 关系的一部分。

BrassPlus 对象都是 Brass 对象,因为它继承了 Brass 对象所有的数据成员和成员函数。所以,可以对 Brass 对象执行的任何操作,都适用于 BrassPlus 对象。因此,为处理 Brass 引用而设计的函数可以对 BrassPlus 对象执行同样的操作,而不必担心会导致任何问题。但需要注意的是,这并不是说,被转换后的基类指针可以使用派生类中的成员函数。假设 BrassPlus 中声明了一个函数 void ResetMax(double m); ,那么下面的用法是不正确的:
  1. BrassPlus dilly ("Annie Dill", 493322, 2000);
  2. Brass *pb = &dilly;  // 正确

  3. pb->ResetMax(3.14);   //错误,基类 Brass 中没有该函数
复制代码
向上强制转换是可以传递的,也就是说,如果从 BrassPlus 派生出 BrassPlusPlus 类,则 Brass 指针或引用可以引用 Brass 对象、BrassPlus 对象或 BrassPlusPlus 对象。


相反的过程 ---- 将基类指针或引用转换为派生类指针或引用 ---- 称为向下强制转换(downcasting)


如果不使用显示类型转换,则向下强制转换是不允许的。原因是,is-a 关系通常是不可逆的。派生类可以新增数据成员,因此使用这些数据成员的类成员函数不能应用与基类。例如,假设从 Employee 类派生出 Singer 类,并添加了表示歌手音域的数据成员和用于报告音域值的成员函数 range(),如果将 range() 方法应用于 Employee 对象是没有意义的,因为 Employee 只是表示所有雇员的一个共性。但如果允许隐式向下强制转换,则可能无意间将指向 Singer 的指针设置为一个 Employee 对象的地址,并使用该指针来调用 range() 方法,如下图所示:





对于使用基类引用或指针作为参数的函数调用,将进行向上转换。如下代码所示(假定每个函数都调用虚方法 ViewAcct()):
void fr(Brass & rb); // uses rb.ViewAcct()
void fp(Brass * pb); // uses pb->ViewAcct()
void fv(Brass b);    // uses b.ViewAcct()
int main()
{
Brass b("Billy Bee", 123432, 10000.0);
BrassPlus bp("Betty Beep", 232313, 12345.0);
fr(b);  // uses Brass::ViewAcct()
fr(bp); // uses BrassPlus::ViewAcct()
fp(b);  // uses Brass::ViewAcct()
fp(bp); // uses BrassPlus::ViewAcct()
fv(b);  // uses Brass::ViewAcct()
fv(bp); // uses Brass::ViewAcct()

...
}

如上所示,如果是按值传递,这会导致只将 BrassPlus 对象的 Brass 部分传递给函数 fv() 。但岁引用和指针发生的隐式向上转换就会导致函数 fr() 和 fp() 分别为 Brass 对象和 BrassPlus 对象使用 Brass::ViewAcct() 和 BrassPlus::ViewAcct() 。

隐式向上强制转换使基类指针或引用可以指向基类对象或派生类对象,因此需要动态联编。C++ 使用虚成员函数来满足这种要求。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-21 12:02 , Processed in 0.065683 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表