类型转换规则
一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:
1、派生类的对象可以隐含转换为基类对象。
2、派生类的对象可以初始化基类的引用。
3派生类的指针可以隐含转换为基类的指针
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| include<iostream> using namespace std; class Base1 {//基类Base1定义 public: void display() { cout << "Base1::display()" << endl; } }; class Base2 :public Base1 {//公有派生类Base2定义 public: void display() { cout << "Base2::display()" << endl; } }; class Derived :public Base2 { public: void display() { cout << "Derived::display()" << endl; } }; void fun(Base1* ptr) { ptr->display(); } int main(void) { Base1 base1; Base2 base2; Derived derived; fun(&base1); fun(&base2); fun(&derived); return 0; }
|
运行结果为:
这个例子说明了通过基类对象名,指针只能使用从基类继承的成员
虚函数
为了解决上面的问题,我们引入虚函数的概念
虚函数
是用virtual关键字说明的函数虚函数是实现运行时多态性基础
1、C++中的虚函数是动态绑定的函数
2、虚函数必须是非静态的成员函数,虚函数经过派生之后,就可以实现运行过程中的多态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Base1{ public: virtural void display(){ cout<<"Base1::display()"<<endl; } } {% u 父类的display是虚函数,子类的Base2,Derived中display函数也自动变成虚函数 %} ![运行结果.png](https: ## 多态性
{% folding 多态性 %} ![父类与子类的关系.png](https: {% endfolding %} ```cpp Person *pPerson[N]; pPerson[0]=new Student(...); pPerson[1]=new Professor(...); for (int i=0;i<N;i++){ pPerson[i]->print(); }
|
如上图所示,F中Continuing
没有print
函数,于是,会制动调用B 中的print()
函数,但是如果B中也没有print
函数,会继续向父类调用,此时输出的是父类的信息。
动态绑定
4动态绑定
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Student:public Person{ void print(int a,int b){} } class Professor:public Person{ void print(int a,int b){} } //main application Person *p; if (some runtime condition) p=new Student; else p= new Professor; p->print(x,y);
|
 在编译时,我们不能预知p指向Student,还是指向Professor。在运行时,通过判断p指向的特定对象是什么,从而决定调用哪个版本的print
函数。
实现动态绑定(多态)的要点:
1.具有类的继承关系图,这个继承关系中每个类都可以调
用一个虚函数;
2.基础类的指针指向子类对象;
3.通过基础类的指针调用虚函数。
只用通过基类的指针或者引用调用虚函数时,才会发生动态绑定
虚析构函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> using namespace std; class Base { public: virtual ~Base(); }; Base::~Base() { cout<< "Base destructor" << endl; } class Derived: public Base{ private: int *p; public: Derived(); ~Derived(); };
Derived::Derived() { p = new int(0); } Derived::~Derived() { cout << "Derived destructor" << endl; delete p; } void fun(Base* b) { delete b; } int main() { Base *b = new Derived(); fun(b); return 0; }
|
1 2 3 4
| class Base { public: ~Base(); };
|
析构函数也应该加上virtual 关键词,可以防止出错