刚刚看了虚继承和虚函数的原理,为了防止遗忘在此浅浅记录。
虚继承
为了防止菱形继承,例如公共父类A,A中有成员int a,B继承A,C继承A,D同时继承B和C,则D中含有两份a,一份来自B,一份来自C,
使用时除非指定是哪个,如D dd; dd.B::a = 1; dd.C::a = 2;
如果使用虚继承,class B :virtual public A,class C :virtual public A,则B,C会创建一个虚基表指针指向虚基表(A),在D中,含有4个区域,B,C区域,这两个区域含有B,C自身的成员以及虚基表指针,还有一个虚基表区域,以及D自身成员区域。
(虚基表指针存放偏移量,B或C区域开始的位置加上偏移量即为目标成员位置)
虚函数(多态)
如果有一个父类A,含有父类成员函数speak(非虚函数),子类B继承父类,子类重写父类函数speak,此时创建一个父类指针指向子类对象,A* a = new B;,a->speak();,调用的还是父类的函数。(原理:C++自动类型转换,仍然为A类型,调用的A的函数)
如果A的speak函数为虚函数,则子类重写父类虚函数后,A* a = new B;,a->speak();,此时调用的为子类的函数。
原理:父类函数定义为虚函数时,在编译阶段编译器增加了一个vptr指针,但此时vptr指针并没有初始化指向虚函数表(vtable),当调用构造函数时,初始化vptr指针,使之指向本对象的虚函数表。若子类没有重写则指向父类的函数,若重写了则覆盖,指向子类的虚函数。、
例如:若有一个父类A,一个父类B,各自含有一个虚函数,当C继承A和B时,若C重写该函数,则实例化C后调用的为C的函数,若无重写则编译器报错,不知道时A还是B的函数。
参考: