内容

1.多态与虚函数
2.虚表

一.多态与虚函数的关系

其实类似于面向对象与类的关系。多态是一种泛型编程思想,而虚函数是实现这种思想的语法基础

说到多态,要记住两句话。
1.多态相当于同样的代码实现不同的功能。
2.最主要的形式就是父类的指针调用子类的函数。(即父类的一个指针,可以有多种执行状态)

代码是这样

class cFather
{
public:
void show()
{
cout << "cFather" << endl;
}

};
class cSon : public cFather
{
public:
void show()
{
cout << "cSon" << endl;
}
};
int main()
{
cFather* fa = new cSon;//特殊点是cFather和cSon类型不同,而之前申请空间都是相同类型。这里特殊,也是实现多态的基础
fa->show();//普通函数调用的话,决定权在指针类型,这里是cFather,所以调用的是父类的show。

system("pause");
return 0;
}

但是这里调用的show不是子类的,而是父类的。所以会打印出cFather。
那么如何调用子类的呢?没错,就是用到虚函数。

二.虚函数

说白了,虚函数就是让父类的指针能够调用子类中的函数成员
注意:虚函数是针对父类与子类函数名相同的那些函数,而不是一般的普通函数。

1.形式

在父类同名函数返回值前面加 virtual

virtual void show()
{
cout << "cFather" << endl;
}

子类和父类有同名的,父类的虚函数,那么fa->show()就是调用的子类的。

class cFather
{
public:
virtual void show()
{
cout << "cFather" << endl;
}

};
class cSon : public cFather
{
public:
void show()
{
cout << "cSon" << endl;
}
};
int main()
{
cFather* fa = new cSon;
fa->show();

system("pause");
return 0;
}

如这个就会打印出cSon

2.注意点

①子类函数返回值,函数名,以及参数列表都要和父类相同(返回值可以不同,但是只有一种写法,并且不常用->协变)

class cFather
{
public:
virtual cFather& show()
{
cout << "cFather" << endl;
return (*this);
}

};
class cSon : public cFather
{
public:
cSon& show()
{
cout << "cSon" << endl;
return (*this);
}
};

②多态是针对于对象指针
③父类的其中一个函数变为虚函数之后,子类的也会变成虚函数,只是没有显示罢了
④构造函数不能是虚函数,虚函数不能是内联函数

3.重写

覆盖是针对类内普通成员,而重写是针对类内虚函数成员

就像上面的那一段代码,我们就可以说对于show函数,子类对父类实现了重写。

4.虚表(虚函数列表)

每个对象都有自己的虚表。虚表里面存着虚函数的地址,需要时直接调用是那个地址的函数



c++学习12 2020-02-01_多态


QQ截图20200201103651.png



过程:

(1)根据父类的指针,找到父类的函数
(2)看父类的函数是不是虚函数
①是->进入虚表,执行表中(自己/重写)
②不是->执行自己

5.取虚表地址以及相应地址的内容(比较难,不必深究)

首先要知道,对象空间最开始四字节内容就是虚表的地址,叫做虚指针。

cFather* fa = new cSon;
*(int*)fa//先找到虚表首地址(因为int也是四字节,所以强转成int类型)

一下就是虚表里的内容了,其实存的都是地址。因为各个地址类型不一样,所以还要强转成一样的,四个字节,即(int)。

cFather* fa = new cSon;
*((int*)*(int*)fa + 0)

使用示例

class cFather
{
public:
virtual cFather& show()
{
cout << "cFather" << endl;
return (*this);
}

};
class cSon : public cFather
{
public:
cSon& show()
{
cout << "cSon" << endl;
return (*this);
}
};
int main()
{
cFather* fa = new cSon;
typedef void (*p)();
((p)(*((int*) * (int*)fa + 0)))();//强转成相应的函数指针类型,也就是p
system("pause");
return 0;
}