原文链接:http://blog.csdn.net/zoopang/article/details/14071779

学过C++的都知道,要实现C++的多态性必须要用到虚函数,并且还要使用引用或者指针,以前学习的时候书本上也是这么说,

但是书本上没有说为什么?   其实只要你认真思考过这个问题你会有三个疑问:

为什么要用虚函数?

为什么要用指针或者引用?

为什么使用派生类和基类对象之间直接赋值不能实现??

一个简单的例子:

  1. class A
  2. {
  3. public:
  4. virtual void print()
  5. {cout<<"A"<<endl;}
  6. };
  7. class B:public A
  8. {
  9. public:
  10. void print()
  11. {cout<<"B"<<endl;}
  12. };
  13. int main()
  14. {
  15. A a;
  16. B b;
  17. A *pa = &b;//能实现多态
  18. pa->print();
  19. a = b; //不能实现多态,为什么?
  20. a.print();
  21. return 0;
  22. }

进一步的,了解C++的人都应该知道只要有虚函数的类就会有一张虚函数表,多态就是通过这张表来实现的。

所以,只要你不断探索下去,就会很快发现前面两个疑问豁然开朗,在这里,我主要探索第三个疑问。

好了,我这里假设你已经对前面两个问题很清楚了。我们进一步把这个问题细化:

程序执行a = b操作时,b中的虚表到底有没有赋给a?

若赋给a了,是不是一定要用指针或引用才能通过虚表调用虚函数?

下面我们通过一个小程序,探索一下:

  1. class A
  2. {
  3. public:
  4. virtual void T(){}
  5. virtual void print()
  6. {cout<<"A"<<endl;}
  7. };
  8. class B:public A
  9. {
  10. public:
  11. void print()
  12. {cout<<"B"<<endl;}
  13. };
  14. int main()
  15. {
  16. A a;
  17. B b;
  18. a = b;
  19. a.print();                         //通过对象直接访问
  20. b.print();
  21. return 0;

首先我们通过调试来看看虚函数表:

程序运行到a=b处时:

我们可以看到B类(派生类)如果覆盖了A类(被继承类)的成员函数,则B类(派生类)的虚函数表第二项(*vtptr[1])的内容也会被覆盖,但是A类(被继承类)的虚函数表的其他表项依然被继承过来,表项的顺序和他们在A类(被继承类)的声明是一致(在这里我不再验证)。

程序运行到a.print()处时:

我们可以看到A类(被继承类)中的虚函数表项并没有被覆盖,也就说没有赋值过来,所以自然的使用a.print()时,也只是调用自己的成员函数。

到这里我们找到了第一个疑问的答案。

既然默认的赋值运算没有实现虚表的赋值,那么我们就重写A类的成员函数operaotor =:

  1. A& operator = (const B& b)
  2. {
  3. *(int *)this=*(int *)&b;
  4. return *this;
  5. }

添加了代码之后,我们继续来运行上面的代码,得到如图的运行结果:

这说明,对象去访问成员的虚函数并不通过虚函数表。

为了验证虚函数表的确传了过去,可以再添加下面两行代码:

  1. A *pa = &a;
  2. pa->print();

输出如下:

到这里为止,提出的疑问基本上已经有了答案。但是,又产生了新的疑问,对象为什么访问不了虚函数表?

一句话解释:

1.默认的赋值运算符并不会操作虚函数表。

2.要实现多态,必须使用指针或者引用。

后话:文章到此结束,对于后面那个疑问,博主我也不知道答案,如果你知道,麻烦留言告知一下,还有就是此文我只是想记录一下我探索的过程,其中可能会有错误,所以如果你发现了错误,请你一定要提出来,以免我误导其他读者,谢谢!

C++中为什么要用虚函数、指针或引用才能实现多态?的更多相关文章

  1. 为什么C++中只有指针和引用才能实现多态?

    代码: class A { public: virtual void Debug(){} }; class B:public A { public: virtual void Debug(){} }; ...

  2. 由剑指offer引发的思考——对象中虚函数指针的大小

    先看一个简单的问题: 一.定义一个空的类型,对于其对象我们sizeof其大小,是1字节.因为我们定义一个类型,编译器必须为其分配空间,具体分配多少是编译器决定,vs是1字节,分配在栈区. 那,这一个字 ...

  3. C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)

    //多态的原理--虚函数指针--子类虚函数指针初始化 #include<iostream> using namespace std; /* 多态的实现原理(有自己猜想部分) 基础知识: 类 ...

  4. 转 C++中不能声明为虚函数的有哪些函数

    传送门 C++中不能声明为虚函数的有哪些函数 常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数 ...

  5. C++中的继承与虚函数各种概念

    虚继承与一般继承 虚继承和一般的继承不同,一般的继承,在目前大多数的C++编译器实现的对象模型中,派生类对象会直接包含基类对象的字段.而虚继承的情况,派生类对象不会直接包含基类对象的字段,而是通过一个 ...

  6. 【转载】 C++多继承中重写不同基类中相同原型的虚函数

    本篇随笔为转载,原文地址:C++多继承中重写不同基类中相同原型的虚函数. 在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: ...

  7. C++中不能声明为虚函数的有哪些函数

    常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数(非成员函数)只能被overload,不能被o ...

  8. 虚函数指针sizeof不为sizeof(void*)

    ref:http://bbs.csdn.net/topics/360249561 一个继承了两个虚基类又增加了自己的一个虚函数pif的类,sizeof(指向pif的指针)竟然是8(X86).我是从这里 ...

  9. C++中构造函数能调用虚函数吗?(答案是语法可以,输出错误),但Java里居然可以

    环境:XPSP3 VS2005 今天黑总给应聘者出了一个在C++的构造函数中调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码: class Base { public: Base() ...

随机推荐

  1. Swf Decrypt详解

    http://www.2cto.com/Article/201507/414477.html 攻击在持续,攻击的技术在演进.防御者需要持续的跟进研究和投入.最近Flash 0day频繁出现,将我们更多 ...

  2. C#集合之ArrayList

    C#中之所以有集合这个东东,是因为数组的长度是固定的,而实际需求是,不确定未来这个“数组”的个数,故出现集合这个概念,因为集合的容量会随元素的增加曾倍数增长.C#中有2类常用集合:ArrayList, ...

  3. 利用sys.dm_db_index_physical_stats查看索引碎片等数据(转)

    我们都知道,提高sql server的数据查询速度,最有效的方法,就是为表创建索引,而索引在对数据进行新增,删除,修改的时候,会产生索引碎片,索引碎片多了,就需要重新组织或重新生成索引,以达到索引的最 ...

  4. Objective-C 学习笔记(Day 3,上)

    ------------------------------------------- 类方法   ①类方法:        + 开头的方法(定义的过程形式和对象方法一样,只不过 + 开头,这是唯一的 ...

  5. JavaScript学习笔记(8)——JavaScript语法之运算符

    一. 算术运算符: 运算符 描述 例子 结果 + 加 x=y+2 x=7 - 减 x=y-2 x=3 * 乘 x=y*2 x=10 / 除 x=y/2 x=2.5 % 求余数 (保留整数) x=y%2 ...

  6. HDU 4763 (KMP算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4763 题目大意:给定一串字符,从中找出符合“EAEBE”格式的E的最大字符数.AB可以是任意数量的任意 ...

  7. C++ Txt文档写入

    void writefile(student *s,int n,string filepath){ ofstream myfile; if(!myfile)//有错误 { exit(1); }else ...

  8. sgu 105 Div 3

    一个数能整除3当且仅当各位数之和能整除3. 有了这个规律就好办了, 但是呢,仔细一看, n太大了, 都到 2^31 了.所以简单的模拟肯定不行. 这种貌似像数论的题,一时找不到好办法,就打表! 打表出 ...

  9. libipq —— iptables用户空间数据包排队库

    LIBIPQ(3) NAMElibipq —— iptables用户空间数据包排队库 SYNOPSIS #include <linux/netfilter.h>#include <l ...

  10. 51nod1089最长回文子串V2

    1089 最长回文子串 V2(Manacher算法) 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 回文串是指aba.abba.cccbccc.aaaa这种左右对称的字 ...