C++语法16-虚函数

虚函数是重载的另一种表现形式。这是一种动态的重载方式,它提供了一种更为灵活的运行时的多态性机制。虚函数允许函数调用与函数体之间的联系在运行时才建立,也就是在运行时才决定如何动作,即所谓的动态联编

1. 虚函数的定义

虚函数就是在基类中被关键字virtual说明,并在派生类中重新定义的函数。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

虚基类的定义是在基类中进行的,它是在基类中需要定义为虚函数的成员函数的声明中冠以关键字virtual。定义虚基类的方法如下:

1
2
3
virtual 函数类型 函数名(形参表){
函数体
}

在基类中的某个成员函数被声明为虚函数后,此虚函数就可以在一个或多个派生类中被重新定义。在派生类中重新定义时,其函数原型,包括函数类型、函数名、参数个数、参数类型的顺序,都必须与基类中的原型完全相同。

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
虚函数的使用
#include<iostream>
using namespace std;
class B0{
public:
virtual void print(char* p){ //定义虚函数print
cout<<p<<"print()"<<endl;
}
};
class B1:public B0{
public:
virtual void print(char* p){ //重新定义虚函数print
cout<<p<<"print()"<<endl;
}
};
class B2:public B1{
public:
virtual void print(char* p){ //重新定义虚函数print
cout<<p<<"print()"<<endl;
}
};
int main(){
B0 ob0,*op;
op=&ob0; op->print("B0::");
B1 ob1;
op=&ob1; op->print("B1::");
B2 ob2;
op=&ob2;op->print("B2::");

return 0;
}

说明:

(1)若在基类中,只声明虚函数原型(需加上virtual),而在类外定义虚函数时,则不必再加virtual。

(2)在派生类中,虚函数被重新定义时,其函数的原型与基类中的函数原型(即包括函数类型、函数名、参数个数、参数类型、参数类型的顺序)都必须完全相同。

(3)C++规定,当一个成员函数被定义为虚函数后,其派生类中符合重新定义虚函数要求的同名函数都自动成为虚函数。因此,在派生类中重新定义该虚函数时,关键字virtual可以写也可以不写。但是,为了使程序更加清晰,最好在每一层派生类中定义该函数时都加上关键字virtual。

(4)如果在派生类中没有对基类的虚函数重新定义,则公有派生类继承其直接基类的虚函数。一个虚函数无论继承多少次,它仍然保持其虚函数的特性。

(5)虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态成员函数,因为虚函数调用要靠特定的对象来决定该激活哪个函数。

(6)虽然使用对象名和点运算符的方式也可以调用虚函数,但是这种调用是在编译时进行的,是静态联编,它没有利用虚函数的特性。只有通过基类的指针访问虚函数时才能获得运行的多态性。

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
使用对象名和点运算符的方式调用虚函数。
#include<iostream>
using namespace std;
class B0{
public:
virtual void print(char* p){
cout<<p<<"print()"<<endl;
}
};
class B1:public B0{
public:
virtual void print(char* p){
cout<<p<<"print()"<<endl;
}
};
class B2:public B1{
public:
virtual void print(char* p){
cout<<p<<"print()"<<endl;
}
}
int main(){
B0 ob0;
ob0.print("B0::");
B1 ob1;
ob1.print("B1::");
B2 ob2;
ob2.print("B2::");

return 0;
}

2. 虚析构函数

在C++中,不能声明虚析构函数,但是可以声明虚析构函数,之前介绍过,当派生类对象撤销时,一般先调用派生类的析构函数,然后再调用基类的析构函数。

-------------The End-------------
0%