c++ virtual关键字学习

virtual在类中使用

如在多继承中(环状继承):

class D{......};
class B: public D{......};
class A: public D{......};
class C: public B, public A{.....};

这个继承会使D创建两个对象,要解决这个问题就可以使用虚拟继承格式:

class D{......};
class B: virtual public D{......};
class A: virtual public D{......};
class C: public B, public A{.....};

虚继承:在创建父类的时候(在创建对象的时候会创建一个虚表)。

#include <iostream>
using namespace std;

class D
{
public:
    D()
    {
        cout << "D()" << endl;
    }
    ~D()
    {
        cout << "~D()" << endl;
    }

protected:
    int d;
};

class B : virtual public D
{
public:
    B()
    {
        cout << "B()" << endl;
    }
    ~B()
    {
        cout << "~B()" << endl;
    }

protected:
    int b;
};

class A : virtual public D
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    ~A()
    {
        cout << "~A()" << endl;
    }

protected:
    int a;
};

class C : public B,
          public A
{
public:
    C()
    {
        cout << "C()" << endl;
    }
    ~C()
    {
        cout << "~C()" << endl;
    }

protected:
    int c;
};

运行测试

int main()
{
    /*
    the order of class constract with keyword virtual: D,B,A,C;
    otherwise: D,B,D,A,C; create class D twice;
    */
    C c;
    cout << "sizeof(c): " << sizeof(c) << endl;
    return 0;
}

测试结果

D()
B()
A()
C()

~C()
~A()
~B()
~D()

 

 virtual在函数中使用

虚函数是c++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。

虚函数可以为private, 并且可以被子类覆盖(因为虚函数表的传递),但子类不能调用父类的private虚函数。虚函数的重载性和它声明的权限无关。

一个成员函数被定义为private属性,标志着其只能被当前类的其他成员函数(或友元函数)所访问。而virtual修饰符则强调父类的成员函数可以在子类中被重写,因为重写之时并没有与父类发生任何的调用关系,故而重写是被允许的。

编译器不检查虚函数的各类属性。被virtual修饰的成员函数,不论他们是private、protect或是public的,都会被统一的放置到虚函数表中。

对父类进行派生时,子类会继承到拥有相同偏移地址的虚函数表(相同偏移地址指,各虚函数相对于VPTR指针的偏移),则子类就会被允许对这些虚函数进行重载。且重载时可以给重载函数定义新的属性,例如public,其只标志着该重载函数在该子类中的访问属性为public,和父类的private属性没有任何关系。

纯虚函数可以设计成私有的(纯虚函数是通过在声明中使用"=0"来指定),不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有覆盖这种纯虚函数的义务,却没有调用它的权利。

如下类Base中加了virtual关键字的函数就是虚拟函数(例如下面例子中的函数print),于是在Base的派生类BaseSub中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。

当基类Base的指针base_prt指向派生类BaseSub的对象时,对base_prt的print函数的调用实际上是调用了BaseSub的print函数而不是Base的print函数。

这是面向对象中的多态性的体现。

class Base
{
public:
    Base() { cout << "Base()" << endl; };
    ~Base() { cout << "~Base()" << endl; };
    virtual void paint() { cout << "paint Base" << endl; };
};

class BaseSub : public Base
{
public:
    BaseSub() { cout << "BaseSub()" << endl; };
    ~BaseSub() { cout << "~BaseSub()" << endl; };
    void paint() { cout << "paint BaseSub" << endl; };
};

测试代码

int main()
{
    Base *base_prt = new BaseSub();
    // call paint() in class BaseSub, because keyword virtual;
    base_prt->paint();
    delete base_prt;
    return 0;
}

运行结果

Base()
BaseSub()
paint BaseSub
~Base()

 

不错的学习内容 内容2

posted @ 2023-01-08 13:27  johnny_zhao  阅读(53)  评论(0编辑  收藏  举报