多态

什么是多态

字面意思就是多种形态,当类之间存在层次结构,通过继承来相互关联时,就会用到多态。多态意味着在调用成员时,会根据调用的函数的对象来执行不同的函数。通俗一点就是同一操作作用于不同的对象,可以产生不同的效果。

C++中的多态性具体体现在运行和编译两个方面。运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。

静态多态

在编译期间完成的,编译器会根据实参的类型去选择调用适合的函数。典型的一种就是函数重载

动态多态

在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。虚函数

多态成立的三个条件

1、要有继承

2、要有函数重写  虚函数

3、要有父类指针(引用) 指向子类对象

多态是设计模式的基础,多态是框架的基础

1、C++中通过virtual关键字对多态进行支持

2、使用virtual声明的函数被重写后即可展现多态特性

class Cat
{
public:
    virtual int Power(){return 10;}
};

class Cat1 :public Cat
{
public:
    virtual int Power(){return 20;}
};

class Cat2 :public Cat
{
public:
    virtual int Power(){return 30;}
};

class Mouse
{
public:
    int Power(){return 25;}
};

void PlayTest(Cat &c,Mouse &m)
{
    if (c.Power() < m.Power())
    {
        cout <<"老鼠跑了" << endl;
    }
    else
    {
        cout <<"老鼠挂了" << endl;
    }
}

//main
{
    Cat1 c1;
    Cat2 c2;
    Mouse m;

    PlayTest(c1, m);
    PlayTest(c2,m);
}

调用结果:

上面的例子中通过比较老鼠和猫之间的力量悬殊,来展示同一种动物的不同状态。在测试阶段传入不同对象根据条件来调用对应的函数。

那么virtual 在这里起到了一个什么作用呢?首先,之前分析过重写(存在继承的父类和子类中有相同函数名的方法),子类中定义了和父类中相同的函数(方法名相同),就是说子类重写了父类的方法。这种情况下,父类中被重写的函数依然会继承给子类,默认情况下子类中重写的函数将隐藏父类中的函数,我们可以通过类名去访问被隐藏的函数

举个例子了解一下virtual的作用:

#include <iostream>
using namespace std;
#pragma warning(disable : 4996)

class Animal
{
public:
    virtual void Call()
    {
        cout << "Animal: Call" << endl;
    }
    void Eat()
    {
        cout << "Animal: Eat" << endl;
    }
};
class Cat:public Animal
{
public:
    virtual void Call()
    {
        cout << "Cat: Call" << endl;
    }
    void Eat()
    {
        cout << "Cat: Eat" << endl;
    }
};

void Action(Animal &al)
{
    al.Call();
    al.Eat();
}

void PlayObj()
{
    Animal al;
    Cat c;

    Action(al);
    Action(c);
}

int main()
{
    PlayObj();

    system("pause");
    return 0;
}

调用结果:

这里我们是通过父类的引用来调用(父类引用可以直接引用子类对象),可以看出在没有使用virtual加以说明时,子类重写了父类的方法并使其隐藏,因此调用的时候会根据对象来对应调用。而用virtual说明后相当于重定义,传入对象后编译器会根据对象的Vptr指针,在所指的虚函数表中查找对应函数函数,并调用。可以去看多态原理探究

为什么要会用到多态

面向对象的三大概念:封装、继承、多态

封装:突破了C语言函数的概念。

继承:代码复用,使用原来写好的代码,提高效率

多态:易于扩展,可维护性高,实际开发中,提倡扩展不提倡修改

多态相关面试题

面试题1:请谈谈你对多态的理解

多态的实现效果

多态:同样的调用语句有多种不同的表现形态;

多态实现的三个条件

有继承、有virtual重写、有父类指针(引用)指向子类对象。

多态的C++实现

virtual关键字,告诉编译器这个函数要支持多态;不是根据指针类型判断如何调用;而是要根据指针所指向的实际对象类型来判断如何调用
多态的理论基础

态联编PK静态联编。根据实际的对象类型来判断重写函数的调用。

多态的重要意义

设计模式的基础 是框架的基石。

实现多态的理论基础 

函数指针做函数参数

C函数指针是C++至高无上的荣耀。C函数指针一般有两种用法(正、反)。

多态原理探究

与面试官展开讨论

 

面试题2:是否类的每个成员函数都声明为虚函数,为什么。

不能声明为虚函数: 普通函数(非成员函数)、静态成员函数、内联成员函数、构造函数、友元函数。析构函数可以是虚的,而且通常声明为虚函数。

普通函数(非成员函数)

只能被重载,不能被重写,在类的外部什么为虚函数也没什么意思。

静态成员函数

对于每个类来说只有一份,所有的对象都共享这个函数,不归某个对象所有,因此也没必要。

内联成员函数

其作用是在调用的位置直接展开,减少函数调用的开销。属于编译时执行,而虚函数是为了在继承后对象能够准确的执行自己的动作,是在运行时才绑定函数。

构造函数

是用来初始化类的对象的,只有在对象生成后才能发挥多态作用。如果构造函数声明为虚的,则表现为在对象还没生成的时候来定义它,则会出现编译错误。另外,构造函数不能被继承。

友元函数

它不属于类的成员函数,不能被继承。

面试题3:构造函数中调用虚函数能实现多态吗?为什么?

首先要明白虚函数的调用原理,它是通过对象的vptr指针来对虚函数表的检查和调用,那么就需要先初始化类的对象。谁在前谁在后?

请点击构造函数中能调用虚函数,能实现多态吗?

面试题4:为什么要定义虚析构函数?

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值