C++中的多态(一)

多态:一词最初来源于希腊语,意思是具有多种形式或形态的情形。通俗的讲,水在不同的温度下所呈现的不同的状态,比如:水在零摄氏度以下是固态的,在0~100度之间是液态的,在100度以上是气态的。

在C++语言中多态有着更广泛的含义

这里写图片描述

【静态多态】:

int Add(int a, int b)
{
    return a + b;
}
float Add(float a, float b)
{
    return a + b;
}
int main()
{
    cout << Add(30, 20) << endl;
    cout << Add(11.10f, 22.20f) << endl;
    return 0;
}

运行结果:
这里写图片描述

静态多态:编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

【动态多态】:

动态绑定:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。
使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实现动态绑定。

下来咱们举一个简单的例子:

class WashRoom//修建厕所
{
public:
    void GoToManWashRoom()
    {
        cout << "Man-->Please Left" << endl;
    }
    void GoToWomanWashRoom()
    {
        cout << "Woman-->Please Right" << endl;
    }
};

class Person//人
{
public:
    virtual void GoToWashRoom(WashRoom & _washRoom) = 0;
};


class Man :public Person//男士往左
{
public:
    virtual void GoToWashRoom(WashRoom & washRoom)
    {
        washRoom.GoToManWashRoom();
    }
};

class Woman :public Person//女士朝右
{
public:
    virtual void GoToWashRoom(WashRoom & washRoom)
    {
        washRoom.GoToWomanWashRoom();
    }
};

void FunTest()
{
    WashRoom washRoom;//找到厕所
    //来了十个人,性别随机
    for (int iIdx = 1; iIdx <= 10; ++iIdx)
    {
        Person* pPerson;//一个人
        int iPerson = rand() % iIdx;//性别随机
        if (iPerson & 0x01)
            pPerson = new Man;//若为男士
        else
            pPerson = new Woman; //若为女士
            pPerson->GoToWashRoom(washRoom);//选择适当方向
        delete pPerson;//销毁对象
        pPerson = NULL;
        Sleep(1000);
    }
}

int main()
{
    FunTest();
    return 0;
}

运行结果:
这里写图片描述

【动态绑定条件】
1、通过基类类型的引用或者指针调用虚函数
这里写图片描述

这里写图片描述

2、必须是虚函数(派生类一定要重写基类的虚函数)

class Base
{
public:
    virtual void FunTest1(int _iTest)
    { 
        cout << "Base::FunTest1()" << endl; 
    }
    void FunTest2(int _iTest)
    { 
        cout << "Base::FunTest2()" << endl; 
    }
    virtual void FunTest3(int _iTest1)
    { 
        cout << "Base::FunTest3()" << endl;
    }
    virtual void FunTest4(int _iTest)
    { 
        cout << "Base::FunTest4()" << endl; 
    }
};
class Derived :public Base
{
public:
    virtual void FunTest1(int _iTest)
    {
        cout << "Derived::FunTest1()" << endl;
    }
    virtual void FunTest2(int _iTest)
    {
        cout << "Derived::FunTest2()" << endl; 
    }
    void FunTest3(int _iTest1)
    { 
        cout << "Derived::FunTest3()" << endl;
    }
    virtual void FunTest4(int _iTest1, int _iTest2)
    {
        cout << "Derived::FunTest4()" << endl;
    }
};
int main()
{
    Base* pBase = new Derived;
    pBase->FunTest1(0);
    pBase->FunTest2(0);
    pBase->FunTest3(0);
    pBase->FunTest4(0);
    pBase->FunTest4(0);
    return 0;
}

运行结果:
这里写图片描述

继承体系同名成员函数的关系:
这里写图片描述

那些成员函数不能定义成虚函数?

(1).友元函数
(2).构造函数
(3).静态成员函数(static)
(4).内联函数(inline)

注:
(1)最好将基类中的析构函数给成virtual;
(2)最好不要使基类的运算符重载给成virtual

总结:
1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同(协变除外)。
2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
3、只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。
4、如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。
5、构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容易混淆。
6、不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。
7、最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)
8、虚表是所有类对象实例共用的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值