浅析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(); 这也很好理解,将基类对象强制转换成派生类对象,但是这样可能导致访问超过基类的大小时,会崩溃的。
相关文章推荐
- Google C++ 编码规范(中文版)
- *leetcode #135 in cpp
- 国内C/C++刷题网站汇总
- C语言正则表达式详解 regcomp() regexec() regfree()详解
- *leetcode #134 in cpp
- c++对象内存布局(虚表和虚指针)
- C++ continue 和 break 的用法
- Win32下C++遍历目录和文件的源码
- C++ 输入字符串和string 类型总结
- C/C++中调用api设置mysql连接的编码方式
- static全解
- C++之类的成员函数的原理
- C++一些基础
- C++泛型和算法
- 数字之和(C++)
- 从C语言快速学PHP
- C++如何生成随机数
- 【最短系列】C++ namespace
- C++之内联函数-inline
- C语言动态库的使用