多态和虚函数 [补档-2022-10-23]

发布时间 2024-01-13 13:46:42作者: 小白同学_C

简述:

  多态分为两类,一种是静态多态(如函数重载,运算符重载,复用函数名等)和 动态多态(派生类和虚函数实现运行时的多态)   静态多态和动态多态的区别是:静态多态的函数地址早绑定,在编译阶段就确定了函数地址。 动态多态的函数地址是晚绑定,即运行阶段确定函数地址。

多态的满足条件:

  有继承关系;子类中重写父类中的虚函数。

虚函数:


  在函数前面加上关键字 virtual 使得其变成虚函数,这样在编译阶段编译器就不能确定函数的调用了,要通过子类来进行调用,这样也满足了函数地址的晚绑定。

多态的使用:


  父类指针或引用指向子类对象。

例子:

点击查看代码
class father //父类

{

​    public:

​       virtual void show(){  //函数加上virtual后就成为了虚函数

​       std::cout<<”父类的调用”<<std::endl;

​    }

};

class son : public father  //子类

{

​    public:

​       void show(){   //子类重新父类的虚函数

​           std::cout<<”子类的调用”<<std::endl;

​       }

};

void doshow(father & s){ //传入什么对象就调用什么东西的函数

​    s.show();

}

void test(){

​    son s;  doshow(s);

}

虚函数表指针和虚函数表

  在新建一个对象时,如果这个对象的所属类中没用任何成员则这个对象的大小为1字节。但是当我们在对应类中写入了一个virtual虚函数,那么这个对象的大小会变为8,这是因为类中多出了一个虚函数表指针(这个指针是隐藏起来的,我们看不到),这个指针的大小为4,但根据内存对齐的规则,它的大小为8。

  虚函数表是在类创建虚函数时出现的。他不在类中,因此就需要类中有一个虚函数表指针指向这个虚函数表。默认情况下虚函数表中都是父类的虚函数代码入口。如果有子类继承父类,那么子类也会继承一份属于自己的虚函数表并且子类中也有一个隐藏的虚函数表指针指向这个表,但是继承的表中的函数代码入口依然是父类的代码函数入口。

  但是如果子类重写了父类中的某个虚函数时,子类的虚函数表中对应的被重写的虚函数会变成子类被重写的虚函数,因此我们再调用这个被重写的虚函数时会优先调用子类重写的虚函数,如果调用子类没有重写的虚函数,那么则默认调用父类的对应的虚函数。

例子:

  如果子类重写了父类的虚函数,那么使用父类指针调用虚函数时,会优先调用子类的虚函数。

​   父类中如果有虚函数,那么父类指针指向子类对象时,假设父类有func1,func2,func3三个虚函数,如果子类重写了父类的func2,func3函数,然后使用父类指针分别调用以上三个函数,那么父类虚函数中没有被重写的func1会调用父类自己的func1,func2和func3会调用子类重写的func2和func3
多态和虚函数

纯虚函数

语法:virtual 函数声明 = 0;

  如果类中用纯虚函数,那么这个类就是一个抽象类,抽象类不能实例化对象,使用我们必须在子类中重写父类中的纯虚函数,否则子类也为抽象类,无法实例化对象。

  个人感觉,虚函数/纯虚函数的作用是当很多个的类都继承于同一个父类/基类时,这些个类都能够有一些相似的地方,但这些类之间可能作用和功能可能会完全不同(高楼,大厦,小洋房,图书馆,体育馆等等,它们都是建筑,但是人都可以在里面,但是这些建筑的作用各不相同)。也许当派生类特别多时应该才能展现出多态的作用吧