[C++] 面向对象的三大特性:封装、继承和多态

简介: [C++] 面向对象的三大特性:封装、继承和多态

一. 过程式和对象式程序设计

🐶 概念:

  • 过程式程序设计(C:从上往下,逐步求精,即按照顺序一步一步的把问题解决;
  • 对象式程序设计(C++:在类中定义成员变量和成员函数,通过定义一个对象的方式来对其变量和函数进行调用的方式 ;

🐭 两者的区别与联系:

  • C中,要用结构(student)的话,需要定义一个属于该结构的变量(学号、姓名、性别、成绩);
  • C++中,当我们要用到类(我们可以把结构叫成“类”)的话,我们不叫定义结构变量,而是叫定义一个对象,该对象不仅包含变量,还可以包含函数(C的结构只能包含变量);

🐹 总结:

(1)C结构C++

(2)C结构变量:int、double等类型C++类对象:成员变量、成员函数(C++类特有)


二. 面向对象式的程序设计

🐝 特性:

  • 封装:突破C函数的概念,用类做函数参数的时候,可以使用对象的属性和对象的方法
  • 继承:A B代码复用,即可以复用前人写的代码
  • 多态:是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。 Person对象买票全价,Student对象买票半价。

因为有了继承多态的出现,对基于对象的程序设计进行了升华,从而有了面向对象式的程序设计

🐜 优点:

  • 易维护:由于继承的存在,即使改变需求,那么维护也只是在局部模块(子类中增加或修改功能函数),所以维护起来是非常方便和较低成本的。
  • 易扩展:如果有一个具有某一种功能的类,就可以扩充这个类,创建一个具有扩充功能的类(子类,继承父类功能的同时可以定义自己的特有功能)。
  • 代码重用:功能是被封装在类中的,类是作为一个独立实体而存在的,因此可以很简单的提供类库,使代码得以重复使用。

三. 继承性

🐾 概述:

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。 在现实生活中也是存在继承关系的,例如:父辈的财产由其后代继承。

💐 特点:

单继承,即一个父亲可以有好多孩子,一个孩子只能有一个父亲,也就是说一个父类可以有好多的子类,一个子类只能有一个父类。

🌸 优点:

  • 继承的出现减少了代码冗余(继承使用父类的变量和功能函数就好,不必自己重新定义一套),提高了代码的复用性。
  • 继承的出现,更有利于功能的扩展(不仅可以继承父类的方法,同时还可以新增属于自己的方法),提升可维护性。
  • 多态的前提(后面讲)

🌷 举例

1.父类Parent

class Parent 
{
  private:
     int a = 20;
  public:    
   void print()
   {
        cout<<"Parent 打印 a "<<a<<endl;
     }
};

2.继承父类的子类Child

#include "Parent.h"
class Child : public Parent 
{
  private:
     int b = 30;
}

3.继承的实现:

void main()
{     
     Child  child;    //定义一个子类的对象     
     child. print();  //通过<对象.>的方式可以调用父类的函数print()
     child.b:        //通过<对象.>的方式可以调用自己的变量
}

四. 多态性

✨ 概念

面向对象中的多态是根据实际的对象类型决定函数调用语句的具体调用目标,同样的调用语句有多种不同的表现形态(含义不同)即为多态。

一般多态是在继承关系中出现的,我们都知道,子类继承父类的时候,通过子类实例化一个对象,其对象是可以调用父类中的变量和功能函数的。

那么大家思考一下,当子类中定义了一个和父类的同名函数时,通过子类对象调用该同名函数时,调用的是父类的函数还是子类自己的函数呢?

即子类和父类中出现同名函数时,子类对象应该调用父类中的同名函数还是调用子类中的同名函数问题,这就是多态性问题。不管是继承还是多态,其实都是对基于对象的编程设计的一种升华。

⭐️ 实现多态的三个条件:

  • 要有继承关系;
  • 被调用的函数必须是虚函数,且完成了虚函数的重写;
  • 调用函数的对象必须是父类指针或者引用(即用父类指针(父类引用)自己指向子类对象,然后使用父类指针(父类引用)进行调用)

在类的定义中,前面有virtual关键字的成员函数称为虚函数;virtual关键字只用在类定义里的函数声明中,写函数体时不用。

virtual关键字与多态又有什么关系呢,下面看一下virtual在类中的用法:

🌟 面向对象新需求 — 多态

首先,看下面父类Parent和子类Child中都定义了一个相同的打印函数print(),那么思考一下最后base->print(); 执行基类or子类谁的打印函数?

1、父类Parent 和继承父类的子类Child

class Parent 
{
  private:
     int a = 20;
  public:    
   void print()
   {
        cout<<"Parent 打印 a "<<a<<endl;
     }
};
class Child : public Parent 
{
  private:
     int b = 30;
  public:    
   void print()
   {
        cout<<"Child 打印 b "<<b<<endl;
     }
}

2、实现函数:

void main()
{
     //定义一个父类的指针
     Parent *base = NULL;
     Parent p1;
     Child  c1;  
     //调用方法1
     base = &p1;     //父类指针调用父类对象
     base->print();  //执行父类打印函数
     base->a = 10;   //改变父类中a的值
     base = &c1;    //父类指针调用子类对象(这是可以的,类型兼容原则)
     base->print(); //思考一下,这里是执行基类or子类的打印函数?  
}

正常我们希望如果父类指针调用父类变量地址,打印父类中的打印函数;如果父类指针调用子类变量地址,那么打印子类中的打印函数。

但最终会发现父类指针无论引用的是基类中的变量地址,还是子类中的变量地址,调用的都是父类中的打印函数

现在,编译器的做法不是我们期望的,那么,我们该如何实现我们前面希望的那样根据实际的对象类型来判断重写函数的调用,即:

  • 如果父类指针指向的是父类对象,则调用父类中的定义的函数
  • 如果父类指针指向的是子类对象,则调用子类中定义的重写函数

解决方案:

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

只需在是上面的父类中的重名函数前加上virtual即可,用法如下:

virtual void print()
{
    cout<<"Parent 打印 a "<<a<<endl;
}

一般在父类中重名函数前加上virtual后,子类中的重名函数前可加可不加,系统默认其写了,最好还是都加上,比较明确。最终就实现了根据实际的对象类型来调用相应的函数了。

总结,要想实现根据实际的对象类型来调用相应的重复函数,需要在父类中的重复函数前加上virtual ,子类重复函数不做要求,但最好都加上

练习案例:

//父类:军人
class  CSoldier
{
public:
  virtual int Attack()
  {
    return 25;
  }
};
//子类:炊事兵
class  CCookingSoldier : public CSoldier
{
public:
  virtual int Attack()
  {
    return 15;
  }
};
//子类:特种兵
class  CSpecialForces : public CSoldier
{
public:
  virtual int Attack()
  {
    return 30;
  }
};
//坏人
class  BadPerson
{
public:
  int Power()
  {
    return 20;
  }
};
void  BattleResult(CSoldier *c, BadPerson *b)
{
  if (c->Attack() > b->Power())
  {
    cout << "战斗结果 :正义必胜" << endl;
  }
  else
  {
    cout << "战斗结果 :小偷胜利" << endl;
  }
}
void main()
{
  CSoldier sol;
  CCookingSoldier  cc;
  CSpecialForces spe;
  BadPerson bp;
    //军人和坏人战斗
  BattleResult(&sol, &bp);
  //炊事兵和坏人战斗
  BattleResult(&cc, &bp);
  //特种兵和坏人战斗
  BattleResult(&spe, &bp);
  system("pause");
}

下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。


目录
相关文章
|
8天前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
51 6
|
1月前
|
编译器 C++
c++中的多态
c++中的多态
|
4天前
|
存储 编译器 C++
【c++】多态(多态的概念及实现、虚函数重写、纯虚函数和抽象类、虚函数表、多态的实现过程)
本文介绍了面向对象编程中的多态特性,涵盖其概念、实现条件及原理。多态指“一个接口,多种实现”,通过基类指针或引用来调用不同派生类的重写虚函数,实现运行时多态。文中详细解释了虚函数、虚函数表(vtable)、纯虚函数与抽象类的概念,并通过代码示例展示了多态的具体应用。此外,还讨论了动态绑定和静态绑定的区别,帮助读者深入理解多态机制。最后总结了多态在编程中的重要性和应用场景。 文章结构清晰,从基础到深入,适合初学者和有一定基础的开发者学习。如果你觉得内容有帮助,请点赞支持。 ❤❤❤
60 0
|
2月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
85 19
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
79 13
|
2月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
68 5
|
25天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
34 16
|
1月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
25天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。