C++--第17课 - 继承与多态 - 上

第17课 - 继承与多态 - 上

引入:    

如果子类定义了与父类中原型相同的函数会发生什么?

1. 函数重写

在子类中定义与父类中原型相同的函数,函数重写只发生在父类与子类之间。

父类中被重写的函数依然会继承给子类,默认情况下子类中重写的函数将隐藏父类中的函数,通过作用域分辨符::可以访问到父类中被隐藏的函数。

#include <cstdlib>

#include <iostream>

using namespace std;

class Parent

{

public:

    void print()

    {

        cout<<"I'm Parent..."<<endl;

    }

};

class Child : public Parent

{

public:

    void print()

    {

        cout<<"I'm Child..."<<endl;

    }

};

int main(int argc, char *argv[])

{

    Child child;

    child.print();

    child.Parent::print();

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

}

运行结果:

I'm Child...

I'm Parent...

当函数遇到兼容性问题的时候:

#include <cstdlib>

#include <iostream>

using namespace std;

class Parent

{

public:

    void print()

    {

        cout<<"I'm Parent..."<<endl;

    }

};

class Child : public Parent

{

public:

    void print()

    {

        cout<<"I'm Child..."<<endl;

    }

};

void howToPrint(Parent* p)

{

    p->print();

}

void run()

{

    Child child;

    Parent* pp = &child;   //赋值兼容性原则,当使用父类的时候都能用子类来代替。

    Parent& rp = child; //Parent类引用,应用Child类对象

    child.print();

    pp->print();  //指针打印

    rp.print();   //引用的打印

}

int main(int argc, char *argv[])

{

    run();

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

}

运行结果:

I'm Child...

I'm Parent...

I'm Parent...

分析:

pp执行child,rp引用child。但是后面的两条语句都没有打印I'm Child...,而是I'm Parent...。

l  问题所在:

(1)      C++与C相同,是静态编译型语言。

(2)      在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象。

(3)      所以编译器认为父类指针指向的是父类对象(根据赋值兼容性原则,这个假设合理)。

(4)      由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象。

(5)      从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数。

对于下面的程序:

void howToPrint(Parent* p)

{

p->print();

}

在编译这个函数的时候,编译器不可能知道指针 p 究竟指向了什么。但是编译器没有理由报错。于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。

2. 程序—函数重写实例(江湖恩怨)

#include <cstdlib>

#include <iostream>

using namespace std;

/*大boss挑战庄主与少庄主*/

class Boss   //大boss

{

private:

    static Boss* cInstance;  //单例模式,就一个 .声明

    Boss()

    {

    }

public:

    static Boss* GetInstance()

    {

        if( cInstance == NULL )

        {

             cInstance = new Boss();

        }   

        return cInstance;

    }

    int fight()

    {

        cout<<"Boss::fight()"<<endl;   //大boss出招

        return 10;

    }

};

Boss* Boss::cInstance = NULL;

//静态变量上面是声明,下面是定义,否则没有意思。

class Master   //庄主

{

public:

    virtual int eightSwordKill() //八剑齐飞

          

    {

        cout<<"Master::eightSwordKill()"<<endl;

        return 8;

    }

};

class NewMaster : public Master //少庄主

{

public:

    virtual int eightSwordKill()

    {

        cout<<"NewMaster::eightSwordKill()"<<endl;

        return Master::eightSwordKill() * 2;

    }

};

void fieldPK(Master* master, Boss* boss)

{

    int k = master->eightSwordKill();

    int b = boss->fight();

    if( k < b )

    {

        cout<<"Master is killed..."<<endl;

    }

    else

    {

        cout<<"Boss is killed..."<<endl;

    }

}

int main(int argc, char *argv[])

{

    Boss* boss = Boss::GetInstance();

    cout<<"Master vs Boss"<<endl;

    Master master;

    fieldPK(&master, boss);

    cout<<"New Master vs Boss"<<endl;

    NewMaster newMaster;

    fieldPK(&newMaster, boss);

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

}

运行结果:

Master vs Boss

Master::eightSwordKill()

Boss::fight()

Master is killed...

New Master vs Boss

NewMaster::eightSwordKill()

Master::eightSwordKill()

Boss::fight()

Boss is killed...

3. 多态的本质

l  面向对象的新需求

根据实际的对象类型来判断重写函数的调用。

如果父类指针指向的是父类对象则调用父类中定义的函数。

如果父类指针指向的是子类对象则调用子类中定义的重写函数。

l  面向对象中的多态

根据实际的对象类型决定函数调用语句的具体调用目标。

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

l  C++中的多态支持

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

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

这就是虚函数。虚函数的特点是,不再只是根据指针类型来判定要使用的函数,而是根据指针所指的内容来判断将要引用的函数。

小结

函数重写是面向对象中很可能发生的情形。

函数重写只可能发生在父类与子类之间。

需要根据实际对象的类型确定调用的具体函数。

virtual关键字是C++中支持多态的唯一方式。

被重写的虚函数即可表现出多态的特性。

猜你喜欢

转载自www.cnblogs.com/free-1122/p/11336223.html