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()