专栏首页架构说实现多态必须满足什么条件

实现多态必须满足什么条件

3 虚函数机制 virtual mechanism 先看代码:

class A
{
public:
 virtual void print() { cout<<"A.."<<endl; }
};
class B : public A
{
public:
 virtual void print() { cout<<"B.."<<endl; }
};
void test4()
{
    A a1; //base
    B  b1;//child 


  a1 = b1;//A::operator= 对象b1赋值给a2
    a1.print(); // prints A
  A& a2=b1;// 引用a2指向b1
    a2.print();//// prints B
}

实现条件:

To get polymorphic behavior in C++, the member functions called must be virtual and objects must be manipulated through pointers or references

Q:

为什么使用派生类和基类对象之间直接赋值不能实现?? 必须用用指针或者引用?

为什么要用虚函数

A:

为什么使用派生类和基类对象之间直接赋值不能实现?? 必须用用指针或者引用?

要实现多态,必须使用指针或者引用 因为默认的赋值运算符并不会操作虚函数表

验证如下:[ Print C++ vtables using GDB]

1.1 vptr 理解成指针 因为不知道vptr内部结果 采用 gdb x查看变量值

因为给出代码只提供一个函数 只需要打印4字节就可以了

(gdb) p sizeof(int) $10 = 4

1.2 打印 A a1; //base

(gdb) p a1

$11 = (A) { _vptr.A = 0x400e10 <vtable for A+16> }

(gdb) x/4x 0x400e10

0x400e10 <_ZTV1A+16>: 0x00400c9e 0x00000000 0x00004231 0x00000000

(gdb) x/4x 0x00400c9e

0x400c9e <A::print()>: 0xe5894855 0x10ec8348 0xf87d8948 0x400dd7be

父类A::_vptr.A 内容是:

0x400c9e <A::print()>

1.3 打印 B b1;//child

执行构造函数:A() -> B()

初始化_vptr

(gdb) p b1 $12 = (B) { = { _vptr.A = 0x400df0 <vtable for B+16> }, } (gdb) x/4x 0x400df0 0x400df0 <_ZTV1B+16>: 0x00400cc8 0x00000000 0x00000000 0x00000000 (gdb) x/4x 0x00400cc8 0x400cc8 <B::print()>: 0xe5894855 0x10ec8348 0xf87d8948 0x400ddbbe

这说明对象b1.vptr 记录虚函数入口地址 0x400cc8 <B::print()>

只要a1.vptr 指向 b1. vptr 即可

1.4 a1=b1

调用 A::operator=

a1 _vptr 没有发生变化 不可以

是不是复制操作有问题这个别人已经验证了 A& operator = (const B& b) { (int )this=(int )&b; return *this; }

依然没有发生变化

1.5 A& a2=b1; 发生发生了什么变化

(gdb) p (B)a2 { = { _vptr.A = 0x400cc8 <B::print()> }, }

(gdb) x/4x 0x400cc8 0x400cc8 <B::print()>: 0xe5894855 0x10ec8348 0xf87d8948 0x400ddbbe

一句话解释: 1.默认的赋值运算符并不会操作虚函数表。 2.要实现多态,必须使用指针或者引用

为什么要用虚函数

如果不没有声明虚函数 同名函数出现覆盖现象!

A& a2=b1; 假如 b1 [AAAA BBBB] a2 [AAAA] A& a2=b1; 对象赋值 只是a.成员=b.成员 其他的就发生强制转换 结果 a2 [AAAA] 函数之间不会赋值的就需要一个记录 函数入口地址

图片可能和代码不符 你应该可以看懂 没有虚函数的对象数据布局

成员类型相同:

成员类型不同(对齐)

有虚函数的对象数据布局

跟深入地方请查看《Inside the C++ Object Model》

我理解

数据部分:

对象在执行赋值 ==操作时候,如果类型不同会发生强制转换

因此需要相同成员

vptr比较特殊 不能像普通成员一样访问

只能通过指针来实现不同对象赋值

通过命令 gdb x 查看 我只声明一个virtual 因此 n=4

如果有清楚麻烦留言告知!

本文分享自微信公众号 - 架构说(JiaGouS),作者:troy

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-04-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • topK总结(初稿)

    问题1 在n个有序数组中,求topK 假定有20个有序数组,每个数组有500个数字,降序排列,数字类型32位uint数值,现在需要取出这10000个数字中最大的...

    程序员小王
  • LeetCode第四题:删除排序数组中的重复项 II

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。

    程序员小王
  • Go语言,Docker和新技术

    上个月,作为 Go 语言的三位创始人之一,Unix 老牌黑客罗勃·派克(Rob Pike)在新文章“Go: Ten years and climbing”中,回...

    程序员小王
  • 使用pm2管理go应用进程

    pm2是一个进程管理工具,可以用它来管理你的node进程,并查看node进程的状态,当然也支持性能监控,进程守护,负载均衡等功能,在前端和nodejs的世界中用...

    特立独行的猫a
  • Nodejs学习笔记(十三)— PM2

    简介   PM2   pm2是一个内置负载均衡的node.js应用进程管理器(也支持Windows),其它的类似功能也有不少,但是感觉pm2功能更强,更值的推荐...

    Porschev
  • pm2在node中的应用

    pm2 是一个带有负载均衡功能的Node应用的进程管理器,当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, pm2是完美的...

    用户1141560
  • 创建无弹窗子进程

    sofu456
  • PM2实用入门指南

    简介 PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。 下面就对PM2进行入门...

    IMWeb前端团队
  • PM2实用入门指南

    PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。

    IMWeb前端团队
  • Node应用的进程管理器: PM2详细介绍

    这里的PM2,不是PM2.5,跟空气没有半毛钱的关系。它是NodeJs应用的进程管理器,可以利用它来简化很多Node应用管理的繁琐任务,如性能监控、自动重启、负...

    Javanx

扫码关注云+社区

领取腾讯云代金券