虚函数和多态

来源:互联网 发布:苹果整理桌面软件 编辑:程序博客网 时间:2024/06/07 14:55
一、虚函数&多态基础
虚函数是加了virtual关键词之后的类成员函数。
虚函数重写:当在子类中定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也叫覆盖)了父类的这个虚函数。

上图中,类Person和类Student中的虚函数Buy一样,且Student继承了Person,所以,Student中的Buy函数重写(覆盖)了Person中的Buy。
至于多态,其形成的条件有来两个:
  1. 使用父类的指针或引用调用虚函数。
  2. 子类的虚函数重写了父类的虚函数(上述被调用函数)。
另外,有关虚函数和多态还有一些需要注意的知识点:
  1. 父类成员函数无virtual时无法构成多态(此时构成重定义),子类中无virtual时可以构成多态(因为子类继承父类,默认子类也是虚函数)。
  2. 父类与子类返回类型(值)不同时,先判断是否是协变,若不是,则调用时编译无法通过。

二、协变
协变:返回值不同,但为父子关系的指针或引用。
eg:
void Person* Buy()
{
}
void Student* Buy()
{
}

调用时:
void Fun (Person* p)
{
    p->Buy();
}

发生协变时,虽然两函数的返回类型(值)不同,但可以成功运行。此时也能构成多态。

三、总结
  1. 子类重写父类的虚函数实现多态,要求函数名、参数列表、返回值完全相同(协变除外)。
  2. 父类中定义了虚函数,在子类中该函数始终保持虚函数的特性。
  3. 只有类的成员函数才能定义为虚函数。
  4. 静态成员函数不能定义为虚函数。(因为没有this指针)
  5. 如果在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual。
  6. 构造函数不能为虚函数,虽然可以将operator=定义为虚函数,但最好不要这样,因为容易在使用时引起混淆。
  7. 不要在构造函数与析构函数里面调用虚函数,在构造函数和析构函数中,对象是不完整的,可能发生未定义的行为。
  8. 最好把父类的析构函数声明为虚函数。
对于第8点,这里作一下简单说明:
eg:
假如~A()函数未加virtual,定义 A* _pa=new B; 然后 delete _pa; ,那么因为~A()未加virtual无法构成多态,所以调析构时,释放空间只与类型有关,此时只调~A()。(正常情况下,调子类的析构时会自动调父类的析构,这样才能清理子类自身中父类的成分)

四、继承体系同名成员函数的关系









原创粉丝点击