C++笔记--类和对象--多态(其一)

多态分为两类:

静态多态,函数重载 和 运算符重载 ,复用函数名。

动态多态, 派生类和虚函数。

平常说的多态大都指的是“动态多态”。

静态多态和动态多态的区别:

静态多态---地址早绑定---编译阶段确定函数的地址。

动态多态---地址晚绑定---运行阶段确定地址。

注:往后的代码main中的情形基本为如下形式

int main()

{

        text01();

        system("pause");

        return 0;

}

目录

1. 多态的基本语法

2. 多态的深入剖析

3. 多态带来的好处


1. 多态的基本语法

        接下来,构建一个场景,方便理解:

//建立一个动物类(父类)
class Animal
{
public:
    //动物会说话
    void speak()
	{
		cout << "动物在说话" << endl;
	}
};
//建一个猫类(子类)
class Cat:public Animal
{
public:
	void speak()
	{
		cout << "小猫喵喵叫" << endl;
	}
};
//建立一个狗类(子类)
class Dog:public Animal
{
public:
	void speak()
	{
		cout << "小狗汪汪叫" << endl;
	}
};
//执行说话的函数
void doSpeak(Animal& a)
{
	a.speak();
}

void text01()
{
	Cat c;
	doSpeak(c);//Animal& a = c
	Dog d;
	doSpeak(d);
}

        如上代码运行之后,呈现的均为Animalspeak函数,而非,猫用猫的,狗用狗的。

        原因:其中的doSpeak函数中的speak函数的地址已经默认为Animal类的了,为早绑定

        做如下修改:

class Animal
{
public:
	//虚函数
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat: public Animal
{
public:
	//此行为称为“重写”  函数的返回值类型、名称、参数列表 与父类虚函数 完全相同
    //此处,打头的virtual可写可不写
	virtual void speak()
	{
		cout << "小猫喵喵叫" << endl;
	}
};

class Dog: public Animal
{
public:
	void speak()
	{
		cout << "小狗汪汪叫" << endl;
	}
};

        在运行,会发现,猫用猫的speak,狗用狗的speak

        原因:此时,地址为晚绑定

综上,动态多态的满足条件:

        1. 有继承关系。

        2. 子类要重写虚函数。

动态多态的使用:

        利用父类的指针引用指向子类的对象。(doSpeak(Animal & a);

2. 多态的深入剖析

        对于Animal.speak,对比没加virtual和加了virtual的大小(sizeof(Animal))。

        会发现前者大小为1(即空类),后者大小为4,其中多了个指针,

        该指针被称为vfptr,v--virtual,f---functon,ptr---pointer,即虚函数(表)指针,

        该指针指向vftable(即虚函数表)(vftable是共享的),表内记录着虚函数的地址。

Animal内部结构:

        vfptr -> vftable

        vftable
        {

                &Animal::speak       

        }

//当子类中出现重写,子类的虚函数表 内部 会将父类的地址替换成子类虚函数的地址

Cat内部结构:

        vfptr -> vftable

        vftable
        {

                &Cat::speak       

        }

//此时父类的指针或引用指向子类时,就会发生多态。

Animal& animal = cat;

animal.speak();

        可以通过查看对象模型来进行验证:

        Animal中无virtual

        Animal中有virtual

        对于Cat (在Animalvirtual的情况下)

        不发生重写

        发生重写

        仔细看会发现,其中,父类虚函数的地址被子类虚函数的地址给覆盖掉了。

3. 多态带来的好处

        接下来,我们通过一个简单的例子来进行分析

//设置一个简易的计算器
class Calculator
{
public:
    //计算器的简单运算原理
	int getResult(string oper)
	{
		if (oper == "+")
		{
			return m_Num1 + m_Num2;
		}
		else if (oper == "-")
		{
			return m_Num1 - m_Num2;
		}
		else if (oper == "*")
		{
			return m_Num1 * m_Num2;
		}
	}
    //输入计算的两个数
	int m_Num1;
	int m_Num2;
};

//实现计算
void text01()
{
	Calculator c;
	c.m_Num1 = 10;
	c.m_Num2 = 20;
    //加法运算
	cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;
}

        以上就是一个普通的简单计算器,可以看出,如果此时,要添加一个除法运算,就需要去源

代码中进行修改,再看一看用多态写的计算器

class Calculator
{
public:
    //虚函数
	virtual int getResult()
	{
        //return什么都无所谓
		return 0;
	}
	int m_Num1;
	int m_Num2;
};

class AddCalculator:public Calculator
{
public:
    //此处的virtual可写可不写,以下均不写
	virtual int getResult()
	{
		return m_Num1 + m_Num2;
	}
};

class SubCalculator :public Calculator
{
public:
	int getResult()
	{
		return m_Num1 - m_Num2;
	}
};

class MulCalculator :public Calculator
{
public:
	int getResult()
	{
		return m_Num1 * m_Num2;
	}
};
//功能演示
void text02()
{
    //多态使用条件:父类的指针或引用指向子类
	Calculator* c = new AddCalculator();
	c->m_Num1 = 10;
	c->m_Num2 = 30;
	cout << c->m_Num1 << " + " << c->m_Num2 << " = " << c->getResult() << endl;
    //因为用new在堆区开辟新的空间,所以最后要delete
	delete c;
    //再看看其他的(减法)
	Calculator* b = new SubCalculator();
	b->m_Num1 = 10;
	b->m_Num2 = 30;
	cout << b->m_Num1 << " - " << b->m_Num2 << " = " << b->getResult() << endl;
	delete b;
}

        对比两种代码可以看到,多态有一个显著的优点,那就是代码量变多了,可以很好地锻炼我

们的手部肌肉,增强手指灵活性,让男程序员、女程序员更好更有力地自我安慰……咳咳。

        言归正传,言归正传,虽然,代码量变多了,但是,他有一个显著的优点,那就是功能区域

,每一个功能都有一个自己的类,组织结构非常的清晰,如果出现了错误,可以很快地找到他的

位置。

        第二个优点就是代码的扩展和维护方便,只需在外部添加或者删除,不需要深入源代码。

        另外,使用多态,还有一个优点,但由于以上示例过于简单的原因,所以看不出来——可读

性强,在实际的工作中,通常都是多人合作完成代码,所以可读性也是非常关键的一点,有句话

怎么说的来着,你写的代码别人一眼就能看明白,不是说明别人有多牛逼,而是体现出你写代码的

能力很强。

        总结,多态的好处有三:结构清晰扩展与维护方便可读性强

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值