免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3407 | 回复: 17

<<Exceptional C++>>条款21的一个疑问 [复制链接]

论坛徽章:
0
发表于 2012-05-02 18:44 |显示全部楼层
10可用积分
条款21: GotW#5 改写虚拟函数(Overriding Virtual Functions)

里面说到: 重载解析程序(overload resolution)是根据静态类型完成的,而不是根据动态类型完成的,所以pb->f(1.0)实际上应该调用Base::f

但是我编程实现,发现调用的是child::f啊。难道书上有误,还是我程序有误?

  1. #include<stdio.h>
  2. struct base{
  3.     virtual void f(int){printf("%s\n",__FUNCTION__);}
  4.     virtual void f(float){printf("%s\n",__FUNCTION__);}
  5.     virtual void g(int){printf("%s\n",__FUNCTION__);}
  6.     virtual ~base(){}
  7. };
  8. struct child: base{
  9.     void f(float){printf("%s\n",__FUNCTION__);}
  10.     void g(int){printf("%s\n",__FUNCTION__);}
  11. };

  12. int main(void)
  13. {
  14.     base* pb=new child;
  15.     pb->f(1.0f);
  16.     pb->f(1);
  17.     pb->g(1);
  18.     delete pb;
  19.         return 0;
  20. }
复制代码

最佳答案

查看完整内容

using这事和你那个问题没关系,using是这样的,见代码:这时打印的会是"child f",因为child f覆盖base f。但如果把child里加上using就会打印出"base f"using可以使base中的函数参与到重载解析中。

论坛徽章:
0
发表于 2012-05-02 18:44 |显示全部楼层
本帖最后由 liwangli1983 于 2012-05-03 10:10 编辑

using这事和你那个问题没关系,using是这样的,见代码:

  1. #include<cstdio>
  2. struct base{
  3.     void f(int){puts("base f");}
  4. };

  5. struct child: base{
  6.     void f(float){puts("child f");}
  7. };

  8. int main(void)
  9. {
  10.     child c;
  11.     c.f(2);
  12.     return 0;
  13. }
复制代码
这时打印的会是"child f",因为child f覆盖base f。
但如果把child里加上using
  1. struct child: base{
  2.     using base::f;
  3.     void f(float){puts("child f");}
  4. };
复制代码
就会打印出"base f"
using可以使base中的函数参与到重载解析中。

论坛徽章:
0
发表于 2012-05-02 18:48 |显示全部楼层
必须是child:f(float)啊,
道友还有什么疑问的??

要么你把那些virtual去掉,就是base::f(float)了.

论坛徽章:
0
发表于 2012-05-02 18:53 |显示全部楼层
本帖最后由 幻の上帝 于 2012-05-03 17:55 编辑

base和child里都有f,除非using base::f;,base里的被child里的隐藏了,实际参与重载解析的只有child::f。
直接写pb->base::f(1.0)就没问题了。

(回帖手残点到编辑了,改回原样。。)

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-05-02 19:31 |显示全部楼层
我觉得你是理解错了,看看这个程序:
  1. #include <iostream>
  2. #include <complex>

  3. struct B {
  4.     virtual ~B() {}
  5.     virtual void f(double) { std::cout << "double f\n"; }
  6. };

  7. struct D : public B {
  8.     virtual void f(int) { std::cout << "int f\n"; }
  9.     virtual void f(std::complex<double>) { std::cout << "complex f\n"; }
  10. };

  11. int main(void)
  12. {
  13.     B *pd = new D;
  14.     pd->f(1);
  15.     delete pd;
  16.     return 0;
  17. }
复制代码
作者的意思是,这个程序应该打印出double f,因为即使pd实际上指向了一个D(拥有接受int参数的f),但是因为重载解析是在编译期完成的,所以编译器实际上只看得到静态类型B*里面具有的方法,也就是一个唯一的double f,也就只会调用这个了,而不是去调用那个看上去“更适合”的int f。

论坛徽章:
0
发表于 2012-05-03 09:16 |显示全部楼层
幻の上帝 发表于 2012-05-02 18:53
base和child里都有f,除非using base::f;,base里的被child里的隐藏了,实际参与重载解析的只有child::f。
...


这个using base::f;应该写在哪里? 我写在child类里面发现还是不行啊:


  1. struct base{
  2.     virtual void f(int){printf("%s\n",__FUNCTION__);}
  3.     virtual void f(float){printf("%s\n",__FUNCTION__);}
  4.     virtual void g(int){printf("%s\n",__FUNCTION__);}
  5.     virtual ~base(){}
  6. };
  7. struct child: base{
  8.     using base::f;
  9.     void f(float){printf("%s\n",__FUNCTION__);}
  10.     void g(int){printf("%s\n",__FUNCTION__);}
  11. };

  12. int main(void)
  13. {
  14.     base* pb=new child;
  15.     pb->f(1.0f);
  16.     pb->g(1);
  17.     delete pb;
  18.         return 0;
  19. }
复制代码

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
发表于 2012-05-03 09:21 |显示全部楼层
我写在child类里面发现还是不行啊
------ 怎么个不行法?

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
发表于 2012-05-03 09:23 |显示全部楼层
回复 3# 幻の上帝


    我觉得你说反了。重载解析是在编译期做的,所以实际上参与重载解析的只有Base里面的函数。

如果了解了C++对象模型这个问题就很直接了。你要认为函数签名也是函数名的一部分,其次虚函数表是一个函数签名->函数指针的哈希表,那么函数签名不一样,自然在这个虚函数表里面的位置也不一样,最终自然取不到对应的东西,这个哈希的过程是编译期做的,而哈希完了以后,取各个类对应的项才是运行时的内容,所以虚函数的签名一定是完全一致的,否则运行期根本就调用不到。lz写的这个例子恰好有两个f签名一致~

论坛徽章:
0
发表于 2012-05-03 09:26 |显示全部楼层
bruceteen 发表于 2012-05-03 09:21
我写在child类里面发现还是不行啊
------ 怎么个不行法?


还是输出child.f

这个using base::f写在哪里才会发挥作用呢?

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
发表于 2012-05-03 09:29 |显示全部楼层
zuiwei 发表于 2012-05-03 09:26
还是输出child.f

难道不应该是 child.f 吗?
除非你改 pb->f(1.0f); 为 pb->f(1);
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP