C++中为什么要用虚函数、指针或引用才能实现多态?

原创 2013年11月07日 21:05:31

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

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

为什么要用虚函数?

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

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

一个简单的例子:

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++中只有指针和引用才能实现多态?

类似代码如下: class A { public:     virtual void Test(){} }; class B:public A { public:    virt...
  • wusecaiyun
  • wusecaiyun
  • 2015年10月05日 23:49
  • 1074

exception in c++

exceptionclass exception {public: exception() throw(); exception(const exception& rhs) throw()...
  • chenhu_doc
  • chenhu_doc
  • 2006年06月03日 20:50
  • 999

C++ 工程实践(4):二进制兼容性http://blog.csdn.net/Solstice/article/details/6233478

C++ 工程实践(4):二进制兼容性 标签: c++libraryinterfacemfcclass编译器 2011-03-09 10:46 17338人阅读 评论(61) 收藏 举报 ...
  • wangyin159
  • wangyin159
  • 2016年02月10日 18:10
  • 552

为什么要使用虚函数和 指针(或是引用)才能实现多态?

首先说说为什么是这样一个题目 最近我在学习《深度探索C++对象模型》这本书,明白了C++对象模型的内存布局。但也恰巧是这个内存布局让我有一次陷入了深深的疑惑之中。先看看我的例子: 注:此例也是引用某位...
  • sangyongjia
  • sangyongjia
  • 2016年03月14日 20:10
  • 1363

C++学习笔记---利用对象、引用、指针调用虚函数

虚函数总结:               虚函数只能是类成员函数,它在基类体内部说明,目的是提供一种接口界面;          虚函数不能是友元函数(即非成员函数),也不能...
  • Weiguang_123
  • Weiguang_123
  • 2014年04月19日 21:51
  • 1713

c++ 虚函数实现多态的原理

前面的文章说过了c++如何实现多态,最主要的就是使用虚函数,另一种方法就是RTTI,这里我们不做说明了。前面说过编译器是这样实现晚绑定的:编译器对每一个含有virtual函数的类创建一个虚函数表vta...
  • u014489596
  • u014489596
  • 2014年08月15日 12:46
  • 1570

ANSI/ISO C++ Professional Programmer's Handbook(7)

  摘自:http://sttony.blogspot.com/search/label/C%2B%2B7运行期类型识别by Danny Kalev 简介 本章的结构 不用RTTI 不要RTTI的支持...
  • SearchLife
  • SearchLife
  • 2008年12月24日 12:17
  • 632

C++虚函数详解&实现机制&多态性

转载:http://blog.chinaunix.net/uid-24178783-id-370328.html
  • tcherry
  • tcherry
  • 2014年10月07日 15:03
  • 1080

C++学习笔记之多态(虚函数)

多态可以分为静态的多态和动态多态,静态多态即所谓的函数重载,在编译阶段即可确定是使用哪个函数。动态多态是通过虚函数来实现的,并基于类的继承来表现。 在使用过程中应注意以下几点: 1、虚函数使用过程中,...
  • ljp1919
  • ljp1919
  • 2015年10月03日 15:16
  • 966

C++为什么要用引用而不是指针

我相信有很多刚学完C,再学C++的人都会有个疑惑,引用是干嘛的,为什么不用指针? 首先,引用 跟 指针 在作用上没有太多区别,作用都是 当遇到较大的 对象(变量)作为函数的 形参 传递时,用...
  • u014453898
  • u014453898
  • 2017年02月06日 14:17
  • 807
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++中为什么要用虚函数、指针或引用才能实现多态?
举报原因:
原因补充:

(最多只允许输入30个字)