多态的概念和作用

本文深入探讨了面向对象编程中的多态概念及其应用,并解释了抽象类与纯虚函数的作用,通过具体示例展示了如何利用多态提高代码的可复用性和可维护性。
     多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
    多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定。再举个比较形象的例子:
    比如有一个函数是叫某个人来吃饭,函数要求传递的参数是人的对象,可是来了一个美国人,你看到的可能是用刀和叉子在吃饭,而来了一个中国人你看到的可能是用筷子在吃饭,这就体现出了同样是一个方法,可以却产生了不同的形态,这就是多态!
多态的作用:
    1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
    2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,以前需要用switch实现

   多态是面向对象程序设计和面向过程程序设计的主要区别之一,何谓多态?记得在优快云里一篇论C++多态的文章里有一名话:“龙生九子,子子不同”多态就是同一个处理手段可以用来处理多种不同的情况,在钱能老师的《C++程序设计教程》书中有这样一个例子:
定义了一个小学生类
[本文全部代码均用伪码]
class Student
{public:
 Student(){}
~Student(){}
 void 交学费(){}
//......
};
里面有一个 “交学费”的处理函数,因为大学生和小学生一些情况类似,我们从小学生类中派生出大学生类:
class AcadStudent:public Student
{public:
 AcadStudent(){}
~ AcadStudent(){}
 void 交学费(){}

//.......
};

我们知道,中学生交费和大学生交费情况是不同的,所以虽然我们在大学生中继承了中学生的"交学费"操作,但我们不用,把它重载,定义大学生自己的交学费操作,这样当我们定义了一个小学生,一个大学生后:

Student A;
AcadStudent B;

A.交学费(); 即调用小学生的,B.交学费();是调用大学生的,功能是实现了,但是你要意识到,可能情况不仅这两种,可能N种如:小学生、初中生、高中生、研究生.....
它们都可以以Student[小学生类]为基类。

如果系统要求你在一群这样的学生中,随便抽出一位交纳学费,你怎么做?

:
 //A为抽出来的要交学费的同学
  {switch(typeof(A))
  {case 小学生:A.小学生:: 交学费 ();break;
   case  初中生:A.初学生:: 交学费 ();break;
   case  高中生:A.高学生:: 交学费 ();break;

   default: 
   .............  
  }
}

首先,我们要在每个类中定义一个 typeof()用来识别它的类型,然后还要在程序中进行区别,这样一来,虽然也行,但是,如果再增加类型则要改动switch,又走了面向过程的老路,而且想通过一个模块进行操作实现起来也有难度。
所以C++中提供了多态,即能通过迟后联编的技术实现动态的区分。
在基类的"交学费"前加个Virtual 用来告诉系统,遇到这个处理过程要等到执行时再确定到底调用哪个类的处理过程。这样一来就可以:

  void 通用的交学费操作 (Student &A)
{A.交学费();
}

一下全部搞定,你再加新的类型我也不怕!!![具体的实现原理参考:《Inside The C++ Object Model》]。如果没有 virtual这一声明,那么,系统在执行前就确定了操作,比如把“大学生”传给 
void 通用的交学费操作 (Student &A)
{A.交学费();
}
,则A.交学费();调用的是大学生类中继承于Student类中的“交学费操作”
所以虚函数对多态的实现是必要的。

为什么会出现纯虚函数呢?

如果按上面的例子进行编程,所有类型都继承小学生类,我们会发现一此小学生自己特定的东东[比如  void 上美术课();],也都被大学生继承来了,虽然不影响大学生的操作,但是随时间的加长,小学生类中自已所特定的东东越来越多,这样下去,大学生中冗余的数据就多了,有什么办法可以解决????

就是定义基类时定义一个抽象类,如学生类,在学生类中实现一此大家都有的操作
。这个过程就叫分解。
这个类子对纯虚函数的说明还不够明显,换个例子比如:

 

class  人()
{public :
 //......
 void 吃()
  {人吃饭;
  }
 //......
 char *Name;
 int age;
};

class  狗()
{public :
 //......
 void 吃()
  {狗吃屎;
  }
 //......
 char *Name;
 int age;
};

人类、狗类有一些相同的东东,如名字,年纪,吃的动作等,有人想到了为了代码的重用,让人类继承狗类,可是数据的冗余让这个想法完蛋了,所以有人又想出可不可以定义一个这样的类:


这个类界于人类狗类之间,有人类和狗类共有的一些东东,比如年纪,名字,体重什么的,但它是不存在实例的,它的存在意义也是只是为了派生其它类,如人类、狗类,这样可以使系统清淅、。。。。。、、反正好处多多。

在这个世界上根本不存在界于人狗之间的东东,所以这个“人狗之间类”中的“吃”也是没什么意义,你也很难为它的内容下个定义,况且也没必要,所以定义它为纯虚函数,形式为:virtual void 吃()=0; 用来告诉系统:
1、这个函数可以没有函数定义;
2、拥有本函数的类是抽象类;
你可能会说,即然纯虚函数没什么意义,为什么还要它,它的作用是什么呢?
为实现多态作准备!!!

由于抽象类的实例没意义,所以C++中不允许定义它的实例。(如果定义了这样的实例A,那么你调用A.吃()怎么办?)


当然了,你也可以在基类中,virtual 吃(){}
这样一来,基类就不是抽象类了,可以有实例,而且对于其它方面都不影响。

但你也要承认这样的对象是没有什么意识的,它的存在只能使你思考上增加负担,除错时还要考虑到是不是有这样类的对象在作怪,所以C++干脆提供了“虚函数”、抽象类,的机制,给我们操作时加了限制也可以认为是保险[不可以有抽象类的对象],试想当代码变得非常之庞大时,它的存在是多么有必要啊!!!

 
<think>嗯,用户问的是封装、继承多态作用。这三个是面向对象编程的核心概念,我得先回忆它们各自的定义应用场景。首先,封装,应该是把数据方法包装起来,对外隐藏实现细节,只暴露接口。这样做的好处应该是提高安全性,比如通过访问修饰符如privatepublic来控制访问权限,防止外部直接修改内部状态。 然后是继承,允许子类继承父类的属性方法,这样可以实现代码的复用,减少重复代码。比如有一个基类Animal,然后DogCat类继承它,这样它们可以共享一些通用的方法,比如eat(),同时可以覆盖或扩展特定的行为。 接下来是多态多态允许不同类的对象对同一消息做出不同的响应。通常通过虚函数运行时动态绑定来实现,比如基类指针指向子类对象,调用虚函数时会执行子类的实现。这样可以提高代码的扩展性灵活性,比如设计一个通用的接口,不同的子类有不同的实现,方便后续扩展。 用户可能是在学习面向对象编程,或者在实际项目中应用这些概念时遇到了问题。需要具体说明每个概念的作用,并且给出例子,这样用户更容易理解。比如封装的例子,用一个类来管理账户余额,确保余额不能被随意修改;继承的例子,用基类子类的关系来展示代码复用;多态的例子,比如绘图程序中不同形状的绘制方法。 另外,用户可能想知道这些特性如何在实际开发中提升效率代码质量。比如封装带来的模块化,使得代码更容易维护;继承减少重复代码;多态使得代码更灵活,易于扩展。可能还要提到这些特性如何协同工作,比如封装的数据通过继承传递,多态在继承的基础上实现不同的行为。 需要确保回答结构清晰,分点解释每个概念的作用,并且举例说明。同时,可能还要对比没有这些特性时的情况,突出它们的优势。比如在没有封装的情况下,数据容易被意外修改;没有继承的话,代码复用性差;没有多态的话,扩展性不足。 最后,用户可能希望了解这些概念的实际应用场景,比如在大型项目中如何利用这些特性进行模块划分设计。或者在面试中常被问到的问题,需要明确且简明扼要的回答。要避免过于技术化的术语,用通俗易懂的语言解释。</think>封装、继承多态是面向对象编程(OOP)的三大核心特性,它们的作用如下: --- ### **1. 封装(Encapsulation)** **作用**:将数据行为包装成独立的单元(类),对外隐藏实现细节,仅暴露必要的接口。 **优点**: - **数据安全性**:通过访问修饰符(如`private`、`protected`)控制外部对内部状态的直接修改。 - **简化使用**:用户只需关注接口,无需了解内部复杂逻辑。 - **模块化**:代码结构清晰,便于维护扩展。 **示例**: ```cpp class BankAccount { private: double balance; public: void deposit(double amount) { if (amount > 0) balance += amount; } double getBalance() { return balance; } }; ``` 外部只能通过`deposit``getBalance`操作余额,无法直接修改`balance`的值。 --- ### **2. 继承(Inheritance)** **作用**:子类(派生类)继承父类(基类)的属性方法,实现代码复用层次化设计。 **优点**: - **代码复用**:避免重复编写通用功能。 - **层次化结构**:通过继承关系清晰表达类之间的关联性。 - **可扩展性**:在不修改基类的前提下,通过子类扩展功能。 **示例**: ```cpp class Animal { public: virtual void speak() { cout << "Animal sound" << endl; } }; class Dog : public Animal { public: void speak() override { cout << "Woof!" << endl; } }; ``` `Dog`类继承`Animal`的接口,并重写`speak`方法。 --- ### **3. 多态(Polymorphism)** **作用**:同一接口在不同对象上表现出不同行为,通常通过虚函数运行时动态绑定实现。 **优点**: - **灵活性**:通过基类指针或引用调用子类方法,实现通用接口设计。 - **可扩展性**:新增子类时无需修改原有代码。 - **解耦**:调用者与具体实现分离,降低代码耦合度。 **示例**: ```cpp void makeSound(Animal* animal) { animal->speak(); // 根据对象类型动态调用对应方法 } Dog dog; Cat cat; makeSound(&dog); // 输出 "Woof!" makeSound(&cat); // 输出 "Meow!" ``` --- ### **三者协同作用** - **封装**是基础,确保数据行为的安全性; - **继承**构建类的层次关系,复用扩展代码; - **多态**通过统一接口实现多样化的行为,提升代码灵活性。 例如,设计一个图形绘制系统: - 封装:每个图形类(如`Circle`、`Square`)封装自己的属性(半径、边长)绘制方法; - 继承:所有图形继承自`Shape`基类; - 多态:调用`draw()`接口时,不同图形自动执行各自的绘制逻辑。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值