类型转换规则

一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:

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;
}

运行结果为:
 程序截图.png
这个例子说明了通过基类对象名,指针只能使用从基类继承的成员

虚函数

为了解决上面的问题,我们引入虚函数的概念
虚函数是用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(){//关键字 virtural
cout<<"Base1::display()"<<endl;
}
}
{% u 父类的display是虚函数,子类的Base2,Derived中display函数也自动变成虚函数 %}
![运行结果.png](https://bu.dusays.com/2023/01/29/63d66cce07cc9.png)
## 多态性

{% folding 多态性 %}
![父类与子类的关系.png](https://bu.dusays.com/2023/01/29/63d66e72e06e3.png)
{% 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);

&emsp;在编译时,我们不能预知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关键词
};

运行结果.png
析构函数也应该加上virtual 关键词,可以防止出错