C++中为什么要用虚函数、指针或引用才能实现多态?
来源:互联网 发布:办公室有老鼠 知乎 编辑:程序博客网 时间:2024/06/06 00:57
但是书本上没有说为什么? 其实只要你认真思考过这个问题你会有三个疑问:
为什么要用虚函数?
为什么要用指针或者引用?
为什么使用派生类和基类对象之间直接赋值不能实现??
一个简单的例子:
class A{public: virtual void print() {cout<<"A"<<endl;}};class B:public A{public: void print() {cout<<"B"<<endl;}};int main(){ A a; B b; A *pa = &b;//能实现多态 pa->print(); a = b; //不能实现多态,为什么? a.print(); return 0;}
进一步的,了解C++的人都应该知道只要有虚函数的类就会有一张虚函数表,多态就是通过这张表来实现的。
所以,只要你不断探索下去,就会很快发现前面两个疑问豁然开朗,在这里,我主要探索第三个疑问。
好了,我这里假设你已经对前面两个问题很清楚了。我们进一步把这个问题细化:
程序执行a = b操作时,b中的虚表到底有没有赋给a?
若赋给a了,是不是一定要用指针或引用才能通过虚表调用虚函数?
下面我们通过一个小程序,探索一下:
class A{public: virtual void T(){} virtual void print() {cout<<"A"<<endl;}};class B:public A{public: void print() {cout<<"B"<<endl;}};int main(){ A a; B b; a = b; a.print(); //通过对象直接访问 b.print(); return 0;}
首先我们通过调试来看看虚函数表:
程序运行到a=b处时:
我们可以看到B类(派生类)如果覆盖了A类(被继承类)的成员函数,则B类(派生类)的虚函数表第二项(*vtptr[1])的内容也会被覆盖,但是A类(被继承类)的虚函数表的其他表项依然被继承过来,表项的顺序和他们在A类(被继承类)的声明是一致(在这里我不再验证)。
程序运行到a.print()处时:
我们可以看到A类(被继承类)中的虚函数表项并没有被覆盖,也就说没有赋值过来,所以自然的使用a.print()时,也只是调用自己的成员函数。
到这里我们找到了第一个疑问的答案。
既然默认的赋值运算没有实现虚表的赋值,那么我们就重写A类的成员函数operaotor =:
A& operator = (const B& b) { *(int *)this=*(int *)&b; return *this; }添加了代码之后,我们继续来运行上面的代码,得到如图的运行结果:
这说明,对象去访问成员的虚函数并不通过虚函数表。
为了验证虚函数表的确传了过去,可以再添加下面两行代码:
A *pa = &a;pa->print();输出如下:
到这里为止,提出的疑问基本上已经有了答案。但是,又产生了新的疑问,对象为什么访问不了虚函数表?
一句话解释:
1.默认的赋值运算符并不会操作虚函数表。
2.要实现多态,必须使用指针或者引用。
后话:文章到此结束,对于后面那个疑问,博主我也不知道答案,如果你知道,麻烦留言告知一下,还有就是此文我只是想记录一下我探索的过程,其中可能会有错误,所以如果你发现了错误,请你一定要提出来,以免我误导其他读者,谢谢!
- C++中为什么要用虚函数、指针或引用才能实现多态?
- C++中为什么要用虚函数、指针或引用才能实现多态?
- C++中为什么要用虚函数、指针或引用才能实现多态?
- 为什么要使用虚函数和 指针(或是引用)才能实现多态?
- 为什么要使用虚函数和 指针(或是引用)才能实现多态?
- 为什么C++中只有指针和引用才能实现多态?
- C++多态机制中虚函数和指针或引用
- 【c++】指针和引用实现多态
- C或C++中函数的参数传递包括:值传递、指针传递、引用传递
- C或C++中函数的参数传递——值传递、指针传递、引用传递
- c++-引用函数指针
- 为什么基类指针(或引用)可以调用派生类的private虚函数
- 【c++】为什么类的定义中不能包含其自身类型,但是能包含其自身的指针或引用类型
- 为什么C++中千万不要返回局部对象或变量的引用和指针
- 为什么C++中千万不要返回局部对象或变量的引用和指针
- C函数常见错误:函数返回指向栈内存的指针或引用
- c中指针与引用
- C/C++ ------ 函数参数 为指针或引用时 强制转化 非常危险
- xCode4.6和xCode5 code theme,好看,不伤眼
- 23个设计模式之代理模式(2)动态代理
- java基础-反射 --通过反射 获取泛型实际类型参数
- 反步法+模糊参数估计设计永磁同步电机控制器(源代码)
- [HDU 4666]Hyperspace[最远曼哈顿距离][STL]
- C++中为什么要用虚函数、指针或引用才能实现多态?
- #R#R presentation and Shiny package
- 开发人员必读的11本最具影响力书籍
- hadoop 单节点安装 Single Node Setup
- ubuntu开启vsftpd以及简单配置
- Touch事件处理
- ListView 自定义头部、自定义加载尾部、上拉主动加载
- 复制二叉树(二叉树)
- 尼克的任务