先上概念,C++的多态性:系统在运行时根据对象类型,来确定调用哪个重载的成员函数的能力。
多态性是通过虚函数实现的。成员函数之前加了virtual,即成为虚函数。
有虚成员函数的类,编译器在其每个对象的开始处自动加一个指针,称为虚表指针,因为它指向一个表,称为虚函数表,表的元素是函数指针,指向该类的虚成员函数代码块。
该类的所有对象共享一张表。关于虚表指针和虚函数表的具体信息,可以参考皓叔的 虚函数表解析 。
虚函数的定义要遵循以下规则:
1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数或者返回类型不同,那么即使加上了virtual关键字,也不会实现多态的。【基类/派生类对象只能直接访问各自定义的函数,虽然派生类对象的虚表里有基类的虚函数指针,但是派生类对象不能调用】 2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。 3.静态成员函数不能是虚函数,因为静态成员函数是属于类的,不属于任意对象。 【静态成员函数也不能是const成员函数,因为编译器会在对象的const函数中自动插入一个const T *this参数,而静态成员函数不属于对象】 4.内联(inline)函数不能是虚函数。即使虚函数在类的内部定义定义,编译的时候系统仍然将它看做是非内联的。【内联函数在编译时可能会展开代码,这样内存的代码区就没有该函数的代码了,已经不是一个函数的概念了,自然虚表里面也没法保存函数指针了】 5.构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。 6.析构函数可以是虚函数,而且通常声名为虚函数。 【有派生类的基类,其析构函数必须为虚函数,这样析构的时候会先析构派生类对象,再析构基类对象,否则派生类的部分就没被析构】
看到上面的规则1,有三个概念要注意:
Overload(重载):将语义、功能相似的几个函数用同一个名字表示,但<参数>或<参数与返回值都>不同(参数个数、类型或顺序不同),即函数重载。 (1)相同的范围(在同一个类中或同一个文件内的普通函数); (2)函数名字相同; (3)参数不同; (4)virtual 关键字可有可无。 Override(覆盖):是指派生类函数覆盖基类函数,只能是虚函数,特征是: (1)不同的范围(分别位于派生类与基类); (2)函数名字相同; (3)返回值和参数相同; (4)基类函数必须有virtual 关键字。 Overwrite(重写):是指派生类的函数屏蔽了与其同名的基类函数,规则如下: (1)如果派生类的函数与基类的函数同名,但是参数不同。不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。 【规则1】 (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
时间: 2024-11-07 20:15:48