虚表:

在C++语言中,每个有虚函数的类或者虚继承的子类,编译器都会为它生成一个虚拟函数表(简称:虚表),表中的每一个元素都指向一个虚函数的地址。(注意:虚表是从属于类的)

此外,编译器会为包含虚函数的类加上一个成员变量,是一个指向该虚函数表的指针(常被称为vptr),每一个由此类别派生出来的类,都有这么一个vptr。虚表指针是从属于对象的。也就是说,如果一个类含有虚表,则该类的所有对象都会含有一个虚表指针,并且该虚表指针指向同一个虚表。

虚表的内容是依据类中的虚函数声明次序--填入函数指针派生类别会继承基础类别的虚表(以及所有其他可以继承的成员),当我们在派生类中改写虚函数时,虚表就受了影响;表中的元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。

说人话就是:含有虚函数的类系统会为其维护一个大小为4字节的虚表指针,指向存放本类的虚函数表,表中存放着本类继承或者重写过的虚函数.

虚函数与重载差异

虚函数:允许子类对父类方法进行重写,如果用一个基类指针指向一个派生类对象时虚表指针指向的是派生类的虚表。(动态联编)

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
class Father{
string name;
int age;
virtual void shout(){
cout<<"the father shout \n";
}
virtual void set_message(string name, int age){
this->name = name;
this->age = age;
}
virtual ~Father(){}
};
class Child{
string sex,name;
int age;
void shout(){
cout<<"the father shout \n";
//严格一致的函数接口构成重写
}
void set_message(string name, string sex,int age){
this->name = name;
this->sex = sex;
this->age = age;
}//由于函数接口不一致(接口指的是参数类型和数量以及返回值类型)
//基类虚函数被隐藏。
};

虚析构函数的作用:

当一个基类指针指向一个派生类对象时,如果直接使用delete p的方式释放对象会导致释放不完全(由于存在派生类虚表的原因)

并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

override的作用:

用于显示说明基类成员函数被重写,强制编译器进行检查。目的:1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。

template继承写法

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
template<class T1, class T2>//参数类型
class Person{
public:
T1 sex;
T2 age;
virtual void set_message(T1 sex, T2 age){
this->sex = sex;
this->age = age;
}
virtual void get_sex(){
cout<<"the Person sex value = "<<sex<<endl;
}
virtual ~Person(){
cout<<"the Person destructor \n";
};
};

template<class T1, class T2>
class Echo: public Person<T1, T2>//参数类型{
public:
T1 name;
T2 age;
T1 sex;

void set_message(T1 sex,T2 name)override{
this->name = name;
this->sex = sex;
cout<<"????????"<<endl;
}
void get_name(){
cout<<"the echo name = "<<name<<endl;
}
void get_sex()override{
cout<<"the Echo sex value = "<<sex<<endl;
}
~Echo(){
cout<<"the Echo destructor \n";
}
};

void template_test(){
Person<string, int> *Vir = new Echo<string,int>;
Vir->set_message("male",20);
Vir->get_sex();
delete Vir;
}