c++中的多态

多态指的是同一个行为,有不同的表现形式,在c++中,要实现多态的函数,必须在其函数前面加上virtual函数,否则,起不到多态作用。

不加virtual关键字的后果:

#include <iostream>
using namespace std;

class Parent
{
public:
	Parent(int a)
	{
		this->a = a;
		cout << "Parent a" << a << endl;
	}

    void print() //子类的和父类的函数名字一样
	{
		cout << "Parent 打印 a:" << a << endl;
	}
protected:
private:
	int a;
};

class Child : public Parent
{
public:
	Child(int b) : Parent(10)   //父类的构造函数中有参数,因此在子类的构造函数中,要进行参数初始化列表
	{
		this->b = b;
		cout << "Child b" << b << endl;
	}
    void print() 
	{
		cout << "Child 打印  b:" << b << endl;
	}
protected:
private:
	int b;
};


void main()
{
	Parent* base = NULL;
	Parent	p1(20);
	Child	c1(30);

	base = &p1;
	base->print(); //执行父类的打印函数

	base = &c1;
	base->print(); //在这里执行的也是父类的打印函数,因为重写的那个函数都没有加virtual关键字

	cout << "hello..." << endl;
	system("pause");
	return;
}

/**
输出:
Parent a20
Parent a10
Child b30
Parent 打印 a:20
Parent 打印 a:10

*/

分析:在上面的代码中,重写的函数print没有加上virtual关键字,然后在main中用parent指针接收的时候,哪怕让它指向一个子类的类型,调用的结果也是父类的print函数,这是因为,这在c++中是静态联编的(没有加virtual关建字的时候),根据指针的类型从而就决定其指向什么类型。(C/C++是静态编译型语言,在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象,在编译此函数的时,编译器不可能知道指针 p 究竟指向了什么。编译器没有理由报错。于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。)

 

但是在加了virtual关键字之后,多态的作用就体现出来,具体代码如下,注意看代码注释:

#include <iostream>
using namespace std;

class Parent
{
public:
	Parent(int a)
	{
		this->a = a;
		cout << "Parent a" << a << endl;
	}

    virtual void print() //子类的和父类的函数名字一样
	{
		cout << "Parent 打印 a:" << a << endl;
	}
protected:
private:
	int a;
};

class Child : public Parent
{
public:
	Child(int b) : Parent(10)   //父类的构造函数中有参数,因此在子类的构造函数中,要进行参数初始化列表
	{
		this->b = b;
		cout << "Child b" << b << endl;
	}
    virtual void print() 
	{
		cout << "Child 打印  b:" << b << endl;
	}
protected:
private:
	int b;
};


void main()
{
	Parent* base = NULL;
	Parent	p1(20);
	Child	c1(30);

	base = &p1;
	base->print(); //执行父类的打印函数

	base = &c1;
	base->print(); //执行子类的print函数,多态的作用就会体现出来

	cout << "hello..." << endl;
	system("pause");
	return;
}

/**
输出:
Parent a20
Parent a10
Child b30
Parent 打印 a:20
Child 打印  b:30

*/

再看另外一个多态的例子:

#include <iostream>
using namespace std;

//HeroFighter  AdvHeroFighter EnemyFighter


class HeroFighter
{
public:
	virtual int power()  //C++会对这个函数特殊处理
	{
		return 10;
	}
};

class EnemyFighter
{
public:
	int attack()
	{
		return 15;
	}
};


class AdvHeroFighter : public HeroFighter
{
public:
	virtual int power()
	{
		return 20;
	}
};

class AdvAdvHeroFighter : public HeroFighter
{
public:
	virtual int power()
	{
		return 30;
	}
};

//多态威力
//1 PlayObj给对象搭建舞台  看成一个框架
//15:20
void PlayObj(HeroFighter *hf, EnemyFighter *ef)
{
	//不写virtual关键字 是静态联编 C++编译器根据HeroFighter类型,去执行 这个类型的power函数 在编译器编译阶段就已经决定了函数的调用
	//动态联编: 迟绑定:  //在运行的时候,根据具体对象(具体的类型),执行不同对象的函数 ,表现成多态.
	if (hf->power() > ef->attack())  //hf->power()函数调用会有多态发生
	{
		printf("主角win\n");
	}
	else
	{
		printf("主角挂掉\n");
	}
}


//多态的思想
//面向对象3大概念
//封装: 突破c函数的概念....用类做函数参数的时候,可以使用对象的属性 和对象的方法 
//继承: A B 代码复用
//多态 : 可以使用未来...


//多态很重要
//实现多态的三个条件
//C语言 间接赋值 是指针存在的最大意义
//是c语言的特有的现象 (1 定义两个变量  2 建立关联  3 *p在被调用函数中去间接的修改实参的值)

//实现多态的三个条件
//1 要有继承 
//2 要有虚函数重写
//3 用父类指针(父类引用)指向子类对象....

void main()
{
	HeroFighter		hf;
	AdvHeroFighter	Advhf;
	EnemyFighter	ef;

	AdvAdvHeroFighter advadvhf;

	PlayObj(&hf, &ef);
	PlayObj(&Advhf, &ef);

	PlayObj(&advadvhf, &ef) ; //这个框架 能把我们后来人写的代码,给调用起来

	cout<<"hello..."<<endl;
	system("pause");

}
void main1401()
{
	
	HeroFighter		hf;
	AdvHeroFighter	Advhf;
	EnemyFighter	ef;
	
	if (hf.power() > ef.attack())
	{
		printf("主角win\n");
	}
	else
	{
		printf("主角挂掉\n");
	}

	if (Advhf.power() > ef.attack())
	{
		printf("Adv 主角win\n");
	}
	else
	{
		printf("Adv 主角挂掉\n");
	}

	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

总结:

多态可以面向未来(只要接口跟以前相同,多态封装成框架之后,可以调用未来的代码),实现多态的3个要求:

(1) 要有继承

(2) 要有虚函数重载

 (3) 要有父类的指针或者引入指向子类对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值