多态的使用和虚函数表

在什么情况下会使用多态,在定义一套接口时,如这个接口void compare(Student &st, StudyBySelf &sb),定义的是父类指针

但是在传入子类指针的时候希望执行的是子类的函数如 compare(pr, sb);,但是if (st.educational() > sb.educational())传入的是pr希望调用Primal这个子类的educational()函数,此时就需要有虚函数了,如果没有virtual关键字那无论你传入的是子类还是父类对象,都只会调用父类的educational()函数。

//多态使用的三个条件

//1、要有继承2、要有虚函数重写3、用父类指针(父类引用)指向子类对象

#include<iostream>

using namespace std;

class Student

{

public:

int knowledge;

public:

virtual int educational()

{

cout << "st knowledge=" << knowledge << endl;

return knowledge;

}

};

class Primal :public Student

{

public:

virtual int educational()

{

cout << "pr knowledge=" << knowledge << endl;

return knowledge;

}

};

class Middle :public Student//1、要有继承

{

public:

virtual int educational()//2、要有虚函数重写   //有virtual关键字  会放入虚函数表中

{

cout << "mi knowledge=" << knowledge << endl;

return knowledge;

}

};

class StudyBySelf

{

public:

int knowledge;

public:

int educational()

{

cout << "sb knowledge=" << knowledge << endl;

return knowledge;

}

};

//多态定义一套接口可以子类父类动态使用

//给对象搭建舞台

void compare(Student &st, StudyBySelf &sb)

{

if (st.educational() > sb.educational())

//这里实现的效果:传来子类的对象则执行子类的educational函数   
//传来父类对象则执行父类的educational函数
//c++编译器根本不区分是子类对象还是父类对象
//父类对象和子类对象分别都有vptr指针===>指针指向虚函数表===>指向函数入口地址

//运行时c++编译器才会去判断是不是虚函数在不在虚函数表中

{

cout << "school is good" << endl;

}

else

{

cout << "self is good" << endl;

}

}

void main2()

{

Student st;//在定义类对象的时候c++编译器会在对象中添加一个vptr指针

st.knowledge = 30;

Primal pr;//子类也会有vptr指针

pr.knowledge = 20;

Middle mi;

mi.knowledge = 40;

StudyBySelf sb;

sb.knowledge = 25;

compare( st, sb);//3、用父类指针(父类引用)指向子类对象

compare(pr, sb);

compare(mi, sb);

system("pause");

}

虚函数表:

1、当类中声明虚函数时,编译器会在类中生成一个虚函数表

2、虚函数表是一个存储类成员函数指针的数据结构

3、虚函数表是由编译器自动生成与维护的

4、virtual成员函数会被编译器放入虚函数表中

5、存在虚函数时,每个对象都有一个指向虚函数表的指针(vptr指针)

编译器确定函数是否为虚函数

1、若函数不是虚函数,编译器课直接确定被调用的成员函数(静态链编,根据父类的类型来确定)

2、函数是虚函数,编译器根据对象的vptr指针所指的虚函数表中查找对应函数,并调用。(查找和调用在运行阶段,是动态链编)

虚函数指针的初始化:1、初始化Primal pr的vptr指针,初始化时分步的

2、当需要执行父类的构造函数时,pr.vptr指向父类的虚函数表,当父类的构造函数

执行完毕后,会把pr.vptr指向子类的虚函数表

3、结论:子类的pr.vptr指针是分步完成的。

不要用父类指针做赋值指针变量,去遍历一个子类数组:

父类的虚函数指针步长和子类虚函数指针的步长的区别,指针步长就是指针的类型,父类虚函数指针的类型是父类类型,子类虚函数指针是子类类型,类类型的大小是指成员变量的大小,在子类继承父类的时候没有添加自己的属性(也就是没有添加自己的成员变量)此时子类虚函数指针的步长和父类虚函数指针的步长一样,但是当子类添加了自己的属性的时候,子类和父类的步长就不一样了。此时在父类指针指向子类对象数组的时候,vptr++就会出错。因为步长不一样。

猜你喜欢

转载自blog.csdn.net/qianyayun19921028/article/details/81007938