免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3602 | 回复: 11
打印 上一主题 下一主题

[C++] 请教个关于多态的问题 [复制链接]

论坛徽章:
7
IT运维版块每日发帖之星
日期:2015-08-29 06:20:00IT运维版块每日发帖之星
日期:2015-08-29 06:20:00平安夜徽章
日期:2015-12-26 00:06:30技术图书徽章
日期:2016-02-03 16:35:252016猴年福章徽章
日期:2016-02-18 15:30:34fulanqi
日期:2016-06-17 17:54:25C
日期:2016-10-25 16:08:32
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-08-18 15:27 |只看该作者 |倒序浏览
#include <iostream>
using namespace std;
  
class A
{
public:
     virtual void f()
     {
         cout << "A" << endl;
     }
};
  
class B: public A
{
public:
     virtual void f()
     {
         cout << "B" << endl;
     }
  
     void e()
     {
         cout << x << endl;
     }
private:
     int x;
};
  
int main()
{
     A *pa = new A();
     B *pb = (B*)pa;
     pb->f();
     pb->e();
}
  
输出结果A和0
问题:
1. pb->f(),一般我们调用都是 基类指针->派生类对象,反过来这么操作,一般应该用dynamic_cast对吧?但是就算不用dynamic_cast,用static_cast或者这种传统转型,也应该出错的吧 ...
2. pb->e(),这个就完全无法理解了,这是A的对象啊 ...

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
2 [报告]
发表于 2015-08-18 19:55 |只看该作者
本帖最后由 MMMIX 于 2015-08-18 21:00 编辑
demilich 发表于 2015-08-18 15:27

  1. pb->f(),一般我们调用都是 基类指针->派生类对象,反过来这么操作,一般应该用dynamic_cast对吧?

没错, 而且应该写成类似如下的形式:

if (B *pb = dynamic_cast<B *>(pa)) {
    ...
} else {
    ...
}

但是就算不用dynamic_cast,用static_cast或者这种传统转型,也应该出错的吧 ...


都是指针, 而且你都做了强制类型转换了...

2. pb->e(),这个就完全无法理解了,这是A的对象啊 ...


pb->e() 是静态绑定, 根据 pb 的类型找到 e(); pb->f() 是动态绑定, 根据 pb 在运行时指向的对象找到 f().

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
3 [报告]
发表于 2015-08-18 20:17 |只看该作者
多恶心的c++。。。我爱c版我不爱c++

论坛徽章:
7
IT运维版块每日发帖之星
日期:2015-08-29 06:20:00IT运维版块每日发帖之星
日期:2015-08-29 06:20:00平安夜徽章
日期:2015-12-26 00:06:30技术图书徽章
日期:2016-02-03 16:35:252016猴年福章徽章
日期:2016-02-18 15:30:34fulanqi
日期:2016-06-17 17:54:25C
日期:2016-10-25 16:08:32
4 [报告]
发表于 2015-08-18 21:25 |只看该作者
回复 2# MMMIX


    那么问题在于,pb->e(); 里面x的值怎么回事?这个是A对象啊,没有x才对,为什么能打印出来?

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-08-18 21:27 |只看该作者
本帖最后由 lxyscls 于 2015-08-19 09:29 编辑

回复 1# demilich
  1. #include <iostream>

  2. using namespace std;

  3. class A
  4. {
  5.     public:
  6.         virtual void f()
  7.         {   
  8.             cout << "A" << endl;
  9.         }   
  10. };

  11. class B: public A
  12. {   
  13.     public:
  14.         virtual void f()
  15.         {   
  16.             cout << "B" << endl;
  17.         }
  18.         
  19.         void e()
  20.         {   
  21.             cout << x << endl;
  22.         }
  23.     private:  
  24.         int x = 10;
  25. };

  26. int main(void)
  27. {
  28.     A *pa = new A;      
  29.     B *pb = (B*)pa;

  30.     pb->f();
  31.     pb->e();

  32.     B *pc = new B();
  33.     pc->e();

  34.     return 0;
  35. }
复制代码
输出是:
A
0
10

GDB:
  1. (gdb) b B::e
  2. Breakpoint 1 at 0x400b1a: file test.cpp, line 24.
  3. (gdb) r
  4. Starting program: /root/cpp/test
  5. A

  6. Breakpoint 1, B::e (this=0x603010) at test.cpp:24
  7. 24                              cout << x << endl;
  8. Missing separate debuginfos, use: debuginfo-install glibc-2.18-19.fc20.x86_64 libgcc-4.8.3-7.fc20.x86_64 libstdc++-4.8.3-7.fc20.x86_64
  9. (gdb) p &x
  10. $1 = (int *) 0x603018
  11. (gdb) x/10 0x603018
  12. 0x603018:       [color=Red]0[/color]       0       0       0
  13. 0x603028:       135137  0       0       0
  14. 0x603038:       0       0
  15. (gdb) c
  16. Continuing.
  17. 0

  18. Breakpoint 1, B::e (this=0x603030) at test.cpp:24
  19. 24                              cout << x << endl;
  20. (gdb) p &x
  21. $2 = (int *) 0x603038
  22. (gdb) x/10 0x603038
  23. 0x603038:       [color=Red]10[/color]      0       0       0
  24. 0x603048:       135105  0       0       0
  25. 0x603058:       0       0
  26. (gdb)
复制代码

论坛徽章:
11
2015年迎新春徽章
日期:2015-03-04 09:55:282017金鸡报晓
日期:2017-02-08 10:39:4215-16赛季CBA联赛之辽宁
日期:2016-12-15 10:24:1715-16赛季CBA联赛之佛山
日期:2016-11-30 09:04:2015-16赛季CBA联赛之江苏
日期:2016-04-29 15:56:1215-16赛季CBA联赛之同曦
日期:2016-04-12 13:21:182016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之山东
日期:2016-02-16 11:37:52每日论坛发贴之星
日期:2016-02-07 06:20:00程序设计版块每日发帖之星
日期:2016-02-07 06:20:0015-16赛季CBA联赛之新疆
日期:2018-01-09 16:25:37
6 [报告]
发表于 2015-08-19 09:05 |只看该作者
pb->e()
其实是
pb->B::e()

实质是
B::e(pb)

类的成员函数,并不属于任何类的实例,而是独一无二的独立的函数
只不过编译器,把this指针隐式的传给它,也就是说语法上的B::e(),其实第一个参数是B*
.....看看python之类语法,就明白了

评分

参与人数 1可用积分 +2 收起 理由
MMMIX + 2 赞一个!

查看全部评分

论坛徽章:
6
技术图书徽章
日期:2013-11-13 11:11:27子鼠
日期:2014-02-20 17:54:13处女座
日期:2014-06-16 17:43:33午马
日期:2014-08-08 09:11:17未羊
日期:2014-08-10 11:57:072015年辞旧岁徽章
日期:2015-03-03 16:54:15
7 [报告]
发表于 2015-08-19 15:14 |只看该作者
这样的强转越界访问,一旦发生bug,绝对会被交叉查错的同事874一百遍啊。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
8 [报告]
发表于 2015-08-19 15:24 |只看该作者
基类指针转型到子类指针不要用dynamic_cast,应该用static_cast,除非你不确定这个指针是不是真的指向一个子类对象。

论坛徽章:
6
技术图书徽章
日期:2013-11-13 11:11:27子鼠
日期:2014-02-20 17:54:13处女座
日期:2014-06-16 17:43:33午马
日期:2014-08-08 09:11:17未羊
日期:2014-08-10 11:57:072015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2015-08-19 15:36 |只看该作者
windoze 发表于 2015-08-19 15:24
基类指针转型到子类指针不要用dynamic_cast,应该用static_cast,除非你不确定这个指针是不是真的指向一个子 ...

除非你有确定指针类型的方法,否则,天知道别人在调用你接口时传入的是不是那个子类型。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
10 [报告]
发表于 2015-08-19 15:58 |只看该作者
本帖最后由 windoze 于 2015-08-19 17:51 编辑

回复 10# littledick

转型前你总得猜一下吧,好多地方都有类似的东西:

  1. struct Base {
  2.     virtual int type_tag()=0;
  3. };

  4. struct Sub1 : public Base {
  5.     virtual int type_tag() { return 1; }
  6. };

  7. struct Sub2 : public Base {
  8.     virtual int type_tag() { return 2; }
  9. };

  10. ...
复制代码
然后用的时候就会这么写:

  1. void f(Base *p) {
  2.     switch(p->type_tag()) {
  3.     case 1: {
  4.         Sub1 *ps1=static_cast<Sub1 *>(p);
  5.         ps1-> ...
  6.     }
  7.     case 2: {
  8.         Sub2 *ps1=static_cast<Sub2 *>(p);
  9.         ps2-> ...
  10.     }
  11.     }
  12. }
复制代码
我知道这段代码很丑,不过重点不在这儿,而是说这段代码里就应该用static_cast,不应该用dynamic_cast

必须用dynamic_cast的地方是这样的:

  1. struct Base1 {
  2.     virtual ~Base1(){}
  3. };
  4. struct Base2 {
  5.     virtual ~Base2(){}
  6. };
  7. struct Sub : public Base1, Base2 { ... };

  8. void f(Base1 *pb1) {
  9.     Base2 *pb2=dynamic_cast<Base2 *>(pb1);
  10.     pb2->...
  11. }
复制代码
上面这段代码必须用dynamic_cast,否则就是错的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP