标签:
首先来看一个实例
1 #include <iostream> 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<assert.h> 5 using namespace std; 6 class A 7 { 8 public: 9 A(){ cout << "A构造函数" << endl; } 10 ~A(){ cout << "A析构函数" << endl; } 11 virtual void print(){ cout << "父类的虚函数" << endl; } 12 void fun(){ cout << "fun a" << endl; } 13 virtual void V_fun(){ cout << "virtual fun a" << endl; } 14 }; 15 class B :virtual public A 16 { 17 public: 18 B(){ cout << "B构造函数" << endl;} 19 ~B(){ cout << "B析构函数" << endl;} 20 void fun(){ cout << "fun b" << endl; } 21 virtual void print(){ cout << "B派生类实现父类的纯虚函数" << endl; } 22 virtual void V_fun(){ cout << "virtual fun b" << endl; } 23 }; 24 class C:virtual public A 25 { 26 public: 27 C(){ cout << "C构造函数" << endl; } 28 ~C(){ cout << "C析构函数" << endl; } 29 void fun(){ cout << "fun c" << endl; } 30 //virtual void print(){ cout << "C派生类实现父类的纯虚函数" << endl; } 31 }; 32 class D :public B,public C 33 { 34 public: 35 D(){ cout << "D构造函数" << endl; } 36 ~D(){ cout << "D析构函数" << endl; } 37 }; 38 int main() 39 { 40 A *a = new B(); 41 a->fun(); 42 a->V_fun(); 43 a->print(); 44 getchar(); 45 return 0; 46 }
虚函数:
函数声明和定义和普通的类成员函数一样,只是在返回值之前加入了关键字“virtual”声明为虚函数。而虚函数是实现多态的重要手段,意思是只有对虚函数的调用才能动态决定调用哪一个函数,这是相对于普通成员函数而言的,普通的成员函数在编译阶段就能确定调用哪一个函数。
基类A有两个成员函数fn和v_fn,派生类B继承自基类A,同样实现了两个函数,然后在main函数中用A的指针指向B的实例(向上转型,也是实现多态的必要手段),然后分别调用fn和v_fn函数。结果是“fn in A"和"virtual fn in B"。这是因为fn是普通成员函数,它是通过类A的指针调用的,所以在编译的时候就确定了调用A的fn函数。而v_fn是虚函数,编译时不能确定,而是在运行时再通过一些机制来调用指针所指向的实例(B的实例)中的v_fn函数。假如派生类B中没有实现(完全一样,不是重载)v_fn这个函数,那么依然会调用基类类A中的v_fn;如果它实现了,就可以说派生类B覆盖了基类A中的v_fn这个虚函数。这就是虚函数的表现和使用,只有通过虚函数,才能实现面向对象语言中的多态性。
虚继承:
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
class 派生类名:virtual 继承方式 基类名
virtual是关键字,声明该基类为派生类的虚基类。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。
语法:
class 派生类: virtual 基类1,virtual 基类2,...,virtual 基类n
{
...//派生类成员声明
};
执行顺序
首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;
执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;
执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;
执行派生类自己的构造函数;
析构以与构造相反的顺序执行;
解决了二义性问题,也节省了内存,避免了数据不一致的问题。
C++虚函数解析:看陈大神的专栏吧http://blog.csdn.net/haoel/article/details/1948051/
标签:
原文地址:http://www.cnblogs.com/jingliming/p/4409640.html