C++的多态

来源:互联网 发布:贝因美积分网络兑换 编辑:程序博客网 时间:2024/05/19 23:02

C++的多态一直是初级程序员的痛,因为总感觉找不到里面的套路。一般讲到的多态往往和虚函数有关,但有的书籍讲到模板和重载也算多态,只不过是静态多态,即在编译器就确定了函数的调用形式。我们这里遵从大多数认为的,也就是前者的动态多态,只有在运行期间才能确定函数的调用。

什么是多态

面向对象编程有三个重要的特点:封装、继承、多态。
这里写图片描述
下面借用http://blog.csdn.net/ruyue_ruyue/article/details/8211809博客的话解释下这些是什么意思。


封装

什么是封装?
封装可以隐藏实现细节,使得代码模块化;封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。在面向对象编程上可理解为:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承

什么是继承?
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。其继承的过程,就是从一般到特殊的过程。
通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承的实现方式?
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
1. 实现继承是指使用基类的属性和方法而无需额外编码的能力;
2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
3. 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。

多态

什么是多态?
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。


什么是重载、覆盖(重写)、隐藏?

重载

重载是一种通过定义同名但是接受不同参数列表的函数,来实现一个统一的调用接口。比如要实现一个加法,需要接受int、float、double、甚至自定义的数据类型,我们的函数只取一个名字add(),但是可以实现多种不同的输入。在外部看来,这里相当于只有一个接口在被调用,不需要只要其实在内部是由不同函数来实现的。必须说明的是,重载是不考虑返回值的。

重载只能发生在一个作用域内部,比如在一在一个类当中。所以,两个类里面是不会发生重载的,就算是继承的关系。

覆盖(重写)

覆盖是指派生类函数覆盖基类函数,特征是:

  • 不同的范围(分别位于派生类与基类);
  • 函数名字相同;
  • 参数相同;
  • 基类函数必须有virtual 关键字。

类如果有虚函数,都会存在虚函数表,有关虚函数表,可以参考这里,
http://www.cnblogs.com/Ripper-Y/archive/2012/05/15/2501930.html
http://my.oschina.net/hnuweiwei/blog/280894
子类在继承父类时,如果父类有虚函数,那么父类的虚函数表会被复制到子类的虚函数表中。所以当基类的函数有virtual时,如果子类也定义了一个同名且参数列表相同(也就是函数签名相同)时,那么基类的虚函数表复制到子类后,这个位置由于与子类签名相同,会被覆盖掉,所以就发生了覆盖。

隐藏

  • (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
  • (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

对于第一条,子类与基类函数签名不同,子类肯定不会去调用基类函数,而且隐藏了父类的该函数。对于第二条,签名相同,基类函数没有使用virtual,则它不在虚函数表中,不可能被覆盖,只是被隐藏了。

为什么需要多态

感觉一个c++有必要整得这么复杂吗?额,我个人感觉相比java,C++过于学究了。为了实现类继承之间的多态性,必须搞得足够复杂才能carry一切。
覆盖的作用很明显,就是子类将基类的虚函数覆盖掉。比如基类定义了很多虚函数接口,然后不同的子类就实现这些接口,这样可以让子类自己定义自己的功能,但是有着统一的接口,很方便管理。
既然有了覆盖,为什么还需要隐藏呢?难道覆盖还不够吗?对,覆盖是将基类的虚函数覆盖掉了,但是有时候不是想覆盖呢?比如,

PS

宏多态

0 0
原创粉丝点击