前端开发入门到精通的在线学习网站

网站首页 > 资源文章 正文

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

qiguaw 2025-01-12 17:55:45 资源文章 18 ℃ 0 评论

虚函数机制 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 virtualand 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

必须使用指针或者引用 为啥它可以如果有清楚麻烦留言告知!

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表