C++中的虚函数

C++中的虚函数

虚函数的使用

虚函数的作用:实现类的多态性

用法:在基类定义虚函数,子类可以重写该函数

在派生类中对基类定义的虚函数进行重写时,需要在派生类中声明该方法为虚方法。

如果使用了virtual关键字,程序将根据引用或指针指向的 对 象 类 型 来选择方法,否则使用引用类型或指针类型来选择方法

eg:

#include<bits/stdc++.h>
using namespace std;
class A {
private:
    int i = 0;
public:
    A(int val) {
        i = val;
    }
    ~A() = default;
    virtual void func1() {
        cout << "A func1" << endl;
    }
    virtual void func2() {
        cout << "A func2" << endl;
    }
    virtual void func2(int val) {
        cout << "#A func2" << endl;
    }
};
class B: public A {

public:
    B(int val): A(val) {};
    // virtual void func1() {
    //     cout << "B func1" << endl;
    // }
    virtual void func2(int val)override {
        cout << "B func2" <<  val << endl;
    }
};
int main() {
    A a(1);
    B b(2);
    A *a_ptr1 = &a;
    A *a_ptr2 = &b;
    
    a_ptr1->func2();
    a_ptr2->func2();

    a_ptr1->func2(2);
    a_ptr2->func2(5);

    a_ptr1->func1();
    a_ptr2->func1();
}

简而言之,如果指针所指向的派生类对象中有该方法就调用该方法,否则就调用基类中的方法

override保留字:override保留字表示当前函数重写了基类的虚函数。

目的

1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);

2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。

注意:override只是C++保留字,不是关键字,这意味着只有在正确的使用位置,oerride才启“关键字”的作用,其他地方可以作为标志符(如:int override;是合法的)。

相关:override还有一个姊妹保留字final。

虚函数的原理

实现原理:虚表指针+虚表函数

编译器处理虚函数的方法是:为每个类对象添加一个隐藏成员,隐藏成员中保存了一个指向函数地址数组的指针,称为虚表指针(vptr),这种数组称为虚函数表(virtual function table, vtbl),即,每个类使用一个虚函数表,每个类对象用一个虚表指针。(这样做会花费格外的存储空间)

基类对象包含一个虚表指针,指向基类中所有虚函数的地址表派生类对象也将包含一个虚表指针,指向派生类虚函数表。看下面两种情况:

如果派生类重写了基类的虚方法,该派生类虚函数表将保存重写的虚函数的地址,而不是基类的虚函数地址。

如果基类中的虚方法没有在派生类中重写,那么派生类将继承基类中的虚方法,而且派生类中虚函数表将保存基类中未被重写的虚函数的地址。注意,如果派生类中定义了新的虚方法,则该虚函数的地址也将被添加到派生类虚函数表中。

TIPS:

总结前面的内容
(1) 基类方法中声明了方法为虚后,该方法在基类派生类中是虚的。
(2) 若使用指向对象的引用或指针调用虚方法,程序将根据对象类型来调用方法,而不是指针的类型。
(3)如果定义的类被用作基类,则应将那些要在派生类中重新定义的类方法声明为虚。
构造函数不能为虚函数。

基类的析构函数应该为虚函数。

友元函数不能为虚,因为友元函数不是类成员,只有类成员才能是虚函数。

如果派生类没有重定义函数,则会使用基类版本。

重新定义继承的方法若和基类的方法不同(协变除外),会将基类方法隐藏;如果基类声明方法被重载,则派生类也需要对重载的方法重新定义,否则调用的还是基类的方法。

什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数 考点:虚函数 析构函数

参考回答:

将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。

C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

请你来说一下静态函数和虚函数的区别

参考回答:

静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销

posted @ 2020-02-12 22:30  buerdepepeqi  阅读(231)  评论(0编辑  收藏  举报