您的位置:首页 > 编程语言 > C语言/C++

浅析C++多态性

2016-06-22 12:28 274 查看

C++多态性 可以简单概括为“一个借口,多种方法”,程序在运行时才决定调用那个函数,这也是C++面对对象编程的核心。

C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义 父类的方式叫 覆盖也称重写
(提醒下:重写有两种:重写成员函数(这叫隐藏),重写虚函数,只有重写虚函数才能算真正体现C++多态性)。

参考:
对于重载、重写(覆盖)、隐藏的理解

多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。

参考:
       早绑定和晚绑定

C++有三大特性:封装,继承,多态
封装实现了代码模块化;继承可以扩展已存在的代码   ------->   他们都是为了实现代码的重用

多态的目的是为了借口重用,也即是,不论传递来的究竟是哪个类对象,函数都能通过同一个接口调用适应各自对象的实现方法。

最常用的方法:声明基类的指针,利用该指针 指向一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。

举例;
#include<iostream>
using namespace std;

class A   //基类
{
public:
void foo()
{
cout << 1 << endl;
}
virtual void fun()  //虚函数
{
cout << 2 << endl;
}
};
class B : public A   //派生类
{
public:
void foo()  //隐藏
{
cout << 3 << endl;
}
void fun()  //重写
{
cout << 4 << endl;
}
};
int main(void)
{
A a;
B b;
A *p = &a; //指向A(基类)
p->foo();  // 调用A(基类)的foo()    输出1
p->fun();  // 调用A(基类)的fun()    输出2

p = &b;  // 指向B(派生类)
p->foo(); //指向A 的foo()            输出1
p->fun(); //指向B 的fun()            输出4
return 0;
}


解析:其实,第一个p-->foo()  和 p-->fun() 很好理解,本身是基类,指向的也是基类的对象,调用本身的函数。
 第二个p-->foo()  和 p-->fun()  分别输出   1  4   ;   p指向的是子类对象,这就体现了多态的用法。在子类中 重写了fun()函数  ,所以调用重写后的fun()函数。   p--->fun()  调用过程:p->fun()指针是基类指针,指向的fun是一个虚函数,由于每个虚函数都有一个虚函数列表,此时p调用fun()并不是直接调用函数,而是通过虚函数列表找到相应的函数的地址,因此根据指向的对象不同,函数地址也将不同,这里将找到对应的子类的fun()函数的地址,因此输出的结果也会是子类的结果4。

上面的测试方法还可以换成 : B*ptr = (B*)&a ;    ptr->foo() ;    ptr->fun();  这也很好理解,将基类对象强制转换成派生类对象,但是这样可能导致访问超过基类的大小时,会崩溃的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: