一、C++为什么引入虚函数,虚函数有哪些用途?
1.非虚的世界
对象的自恰性:对同样的函数调用,每个对象都会做出恰当的响应.
b. 通过指向子类对象的基类指针调用函数:
只能调用基类的成员函数,虽然指针指向子类对象.
一旦调用子类所特有的成员函数,将引发编译错误.
c.通过指向基类对象的子真调用函数:
可以调用子类的成员函数,尽管指针指向基类对象.
直接或简介地访问子类的成员变量,后果不可预知
d.名字隐藏
子类的成员函数隐藏基类的同名的成员函数.
#include <iostream> #include <string> using namespace std; class Base { public: Base(int data = 0):m_data(data){} void print(void) const { cout << m_data << endl; } private: int m_data; }; class Derived:public Base { public: Derived(int data,const string& info): Base(data),m_info(info){} void show(void) const { print(); cout << m_info << endl; } void foo(void) { cout << "Derived::foo(void)" << endl; // m_info = "abc"; } private: string m_info; }; int main(void) { Base b(100); Derived *pd = static_cast<Derived*>(&b); /*子类的指针指向父类*/ /*pd->show();*/ /*这里可以成功调用但是调用的结果是未定义的 因为编译器在调用的时候只看类型. */ pd = NULL; pd->foo(); //这里是可以的,因为编译器在编译的时候只看类型. ((Derived*)0)->foo(); /*函数并不存在于对象中,调用成员函数的时候, 只要调用的类型是对的,就可以根据类型调用相应的 成员函数.但是这种情况之下不能访问成员变量*/ return 0; }
2. 虚函数和名字隐藏
class 类名
{
virtual 返回类型 函数名(形参表){...}
}
的成员函数,称为虚函数或方法
覆盖:
如果子类的成员函数和基类的虚函数具有相同的函数原型,那么该成员
函数就也是虚函数,无论其是否有virtual关键字,且对基类的虚函数
构成覆盖.
还有一种就是如果没有virtual的时候,只要函数名相同就会形成覆盖.
3.多态
如果子类提供了对基类虚函数的有效覆盖,那么通过一个指向子类对象的基类指针,
或者引用子类对象的基类引用,调用该虚函数,实际被调用的将是子类中覆盖
版本,而非基类中的原始,这种现象称之为多态.
多态的重要意义在于,一般的情况下,调用哪个类的成员函数是由调用者指针或引用
本身的类型决定的,而当多态发生的时候,调用哪个类的成员函数则
完全由调动者指针或引用的实际目标对象的类型决定的.
4.有效的虚函数的覆盖要满足如下的条件
该函数必须是成员函数,既不能是全局函数也不能是静态成员函数.
该函数必须在基类中用vitual关键字声明为虚函数
覆盖版本与基类版本必须拥有完全相同的签名,即是函数名,行参表和常属性严格一致.
如果基类版本返回基本数据类型,那么覆盖版本必须返回相同的类型的数据.
如果基类版本返回类类型对象的指针或引用,那么覆盖版本可以返回
其子类类型对象的指针或引用.
虚函数(1)