继承与多态(上)

函数重写

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

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

#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(); //调用父类的print()函数
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

在这里插入图片描述

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

当函数重写遇上赋值兼容性原则

#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;
    
    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 Parent…"哪?

问题所在

C++与C相同,是静态编译型语言
在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象
所以编译器认为父类指针指向的是父类对象(根据赋值兼容性原则,这个假设合理)
由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象
从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数

编译器角度分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-07vJzRV9-1582509300996)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582450010009.png)]

问题:编译器的做法是我们期望的吗?

函数重写实例 江湖恩怨

#include <cstdlib>
#include <iostream>

using namespace std;


//Boss逍遥王 
class Boss{
private:
	static Boss* cInstance;	

public:	
	Boss() {
		
	}
	
	static Boss* GetInstance() {
		if(cInstance == NULL){
			cInstance = new Boss();
		}
		
		return cInstance;
	}
	
	int Fight(){
		return 10;
	}
}; 
Boss* Boss::cInstance  = NULL;


// 老庄主 
class Master{
public:
	int eightSwordKill(){
		return 8;
	}
};
//少庄主 
class NewMaster: public Master{
public:
	int eightSwordKill(){ //新版的八剑齐飞 
		return Master::eightSwordKill() * 2;
	}				
};

//比赛擂台 
void filedPK(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(){
	cout << "Master vs Boos"<<endl;
	Boss* boss = Boss::GetInstance();	
	Master master;	
	filedPK(&master, boss);
	
	cout << "NewMaster vs Boos"<<endl;
	NewMaster newMaster;	
	filedPK(&newMaster, boss); //此处谁会赢哪? 
	 
	
	return 0;
}

在这里插入图片描述
疑问:为什么还是调用的老庄主版本的八剑齐飞那?

多态的本质

面向对象的新需求
根据实际的对象类型来判断重写函数的调用
如果父类指针指向的是父类对象则调用父类中定义的函数
如果父类指针指向的是子类对象则调用子类中定义的重写函数

面向对象中的多态
根据实际的对象类型决定函数调用语句的具体调用目标

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bi6OeGOF-1582509300999)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582507947794.png)]

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

C++中的多态支持
C++中通过virtual关键字对多态进行支持
使用virtual声明的函数被重写后即可展现多态特性

​ 真相只有一个!

​ 这就是传说中的虚函数!

#include <cstdlib>
#include <iostream>

using namespace std;

class Boss
{
private:
    static Boss* cInstance;
    
    Boss()
    {
    }
public:
    static Boss* GetInstance()
    {
        if( cInstance == NULL )
        {
             cInstance = new Boss();
        }
        
        return cInstance;
    }
    
    int fight()
    {
        cout<<"Boss::fight()"<<endl;
        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 10 * 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;
}

在这里插入图片描述

小结

函数重写是面向对象中很可能发生的情形
函数重写只可能发生在父类与子类之间
需要根据实际对象的类型确定调用的具体函数
virtual关键字是C++中支持多态的唯一方式
被重写的虚函数即可表现出多态的特性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值