多态 C++

本文详细介绍了C++中的多态概念,包括虚函数的定义、条件、重写(覆盖)、override和final关键字,抽象类的使用,以及动态绑定与静态绑定的区别。同时解答了关于多态常见面试题,如虚函数的限制和抽象类的作用。
摘要由CSDN通过智能技术生成

多态 C++

多态的定义

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了

Person。Person对象买票全价,Student对象买票半价。

多态的条件:

  1. 必须通过基类的指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

**虚函数:**即被virtual修饰的类成员函数称为虚函数

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

class Person {
public:
 virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
 virtual void BuyTicket() { cout << "买票-半价" << endl; }
};

虚函数重写的两个例外:1.协变(基类与派生类虚函数返回值类型不同) 了解即可

2.析构函数的重写 理解

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,

都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,

看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处

理,编译后析构函数的名称统一处理成destructor。

#include <iostream>
using namespace std;
class Person {
public:
	 ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
	 ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
// 数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	return 0;
}
override和final关键字

override:检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错

final:修饰虚函数,表示该虚函数不能再被重写

抽象类

包含纯虚函数的类就是抽象类,抽象类无法实例化对象,纯虚函数就是在虚函数后面写上=0。派生类继承抽象类后必须重写纯虚函数,否则也是抽象类,无法实例化对象。

class Car
{
public:
virtual void Drive() = 0;
};
class Benz :public Car
{
public:
 virtual void Drive()
 {
 cout << "Benz-舒适" << endl;
 }
};
class BMW :public Car
{
public:
 virtual void Drive()
 {
 cout << "BMW-操控" << endl;
 }
};
void Test()
{
Car* pBenz = new Benz;
 pBenz->Drive();
 Car* pBMW = new BMW;
 pBMW->Drive();
}
多态的原理

虚函数表:一个含有虚函数的类中都至少有一个虚函数表指针,虚函数的地址要被放到虚函数表中。

虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一个nullptr。

总结一下派生类的虚表生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生

类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己

新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。

动态绑定与静态绑定
  1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为也称为静态多态

比如:函数重载

  1. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体

行为,调用具体的函数,也称为动态多态

继承和多态常见面试题

1.什么是多态

2.什么是重载、重写、重定义

3.多态的实现原理

4.inline函数可以是虚函数吗?答:可以,不过编译器就忽略inline属性,这个函数就不再是inline,因为虚函数要放到虚表里去。

5.静态成员可以是虚函数吗?答:不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。

6.构造函数可以是虚函数吗?答:不可以,因为虚函数表指针是在初始化列表才初始化的。

7.析构函数可以是虚函数吗?答:可以,并且最好定义成虚函数。

8.对象访问普通函数快还是虚函数快?答:如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。

9.虚函数表是在什么阶段生成的,存在哪的?答:虚函数表是在编译阶段就生成的,一般情况下存在代码段(常量区)的。

10.什么是抽象类?抽象类的作用?答:抽象类的定义参考上面。抽象类强制重写了虚函数,另外抽

象类体现出了接口继承关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值