多态(1)--多态的基本概念

本文详细介绍了C++中多态的基本概念及其实现方法。包括多态的定义、赋值兼容规则、多态的实现条件及意义等。并通过示例代码展示了如何利用virtual关键字实现多态。

1 多态的基本概念

1.1 什么是多态

如果有几个上似而不完全相同的对象,有时人们要求在向它们发出同一个消息时, 它们的反应各不相同,分别执行不同的操作。这种情况就是多态现象。

C++中所谓的多态(polymorphism)是指,由继承而产生的相关的不同的类,其对象 对同一消息会作出不同的响应。

多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性。可以减轻系统升级,维护,调试的工作量和复杂度。

1.2 赋值兼容(多态实现的前提) ★★

赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。

赋值兼容是一种默认行为,不需要任何的显示的转化步骤。

赋值兼容规则中所指的替代包括以下的情况:

  1. 派生类的对象可以赋值给基类对象。  ︎
  2. 派生类的对象可以初始化基类的引用。  
  3. 派生类对象的地址可以赋给指向基类的指针。

在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员

#include <iostream>
using namespace std;

// 基类
class Animal
{
public:
    void speak()
    {
        cout << "动物在说话" << endl;
    }
};

// 派生类
class Cat : public Animal
{
public:
    void speak()
    {
        cout << "小猫在说话" << endl;
    }   
};

// 形参为基类对象
void doSpeak1(Animal animal)
{
    animal.speak();
}

// 形参为基类的引用
void doSpeak2(Animal &animal)
{
    animal.speak();
}

// 形参为基类的指针
void doSpeak3(Animal *animal)
{
    animal->speak();
}

int main()
{
    // 派生类对象
    Cat cat;
    //  1. 派生类的对象可以赋值给基类对象。 ︎ 
    doSpeak1(cat);

    // 2. 派生类的对象可以初始化基类的引用。  
    doSpeak2(cat);

    // 3. 派生类对象的地址可以赋给指向基类的指针。
    doSpeak3(&cat);

	return 0;
}

在这里插入图片描述
可以看到,虽然传入的是子类的对象,但调用的还是父类的成员函数。这是因为,此编译为静态联编,在编辑阶段已经将成员函数的地址绑定。

1.3 面向对象的新需求

上面的代码,编译器的做法不是我们期望的。

我们期望的是,根据实际的对象类型来判断重写函数的调用

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

在这里插入图片描述

1.4 解决方法 --多态(多态的实现) ★★

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

#include <iostream>
using namespace std;

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

// 派生类
class Cat : public Animal
{
public:
    // 重写虚函数
    void speak()
    {   
        cout << "小猫在说话" << endl;
    }
};

// 注意:此出形参为父类的引用或者指针,否则无法调用子类的成员函数
void doSpeak(Animal &animal)
{
    animal.speak();
}

int main()
{
    // 派生类对象
    Cat cat;
    doSpeak(cat);	// 1.传入子类对象,使父类引用指向子类对象
    
	/*
	Animal *p = new Cat;	// 2.使父类指针指向子类成员
	p->speak();
	delete p;
	*/

    // 基类对象
    Animal animal;
    doSpeak(animal);

	/*
	Animal *p = new Animal;	// 使父类指针指向父类成员
	p->speak();
	delete p;
	*/
    return 0;
}

在这里插入图片描述

1.5 多态工程的意义

封装
 突破了c语言函数的概念。


继承
 代码复用,复用原来写好的代码。


多态
 多态可以使用未来,80年代写了一个框架,90人写的代码。
 多态是软件行业追寻的一个目标。


1.6 多态成立的条件 ★★

  1. 要有继承
  2. 要有虚函数重写
  3. 要有父类指针(父类引用)指向子类对象 // Perant *pP = new Son;

1.5 静态联编和动态联编 ★

  1. 联编是指一个程序模块、代码之间互相关联的过程。 
  2. 静态联编(static binding),是程序的匹配、连接在编译阶段实现,也称为早期匹配。重载函数使用静态联编。 
  3. 动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编(迟绑定)。switch 语句、 if 语句和多态的实现是动态联编的例子。 
  1. C++与C相同,是静态编译型语言
  2. 在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象;所以编译器认为父类指针指向的是父类对象。
  3. 由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象,从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数。这种特性就是静态联编。
  4. 多态的发生是动态联编,实在程序执行的时候判断具体父类指针应该调用的方法。


2 对于多态的理解和总结

2.1 多态的实现效果 ★

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

2.2 多态实现的三个条件 ★★

有继承、有virtual重写、有父类指针(引用)指向子类对象。

2.3 多态的c++实现 ★★

virtual关键字,告诉编译器这个函数要支持多态;

不是根据指针类型判断如何调用;

而是要根据指针所指向的实际对象类型来判断如何调用。

2.4 多态的理论基础

动态联编PK静态联编。根据实际的对象类型来判断重写函数的调用。

2.5 多态的意义

设计模式的基础 是框架的基石。

2.6 多态原理探究

虚函数表(vftable)和虚函数指针(vfptr指针)。 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值