Skip to main content

抽象、封装、继承、多态

抽象(Abstraction)

  • 数据抽象是C ++中面向对象编程的最基本和最重要的功能之一。抽象意味着仅显示基本信息并隐藏细节。数据抽象是指仅向外界提供有关数据的基本信息,隐藏背景细节或实现。

例如车辆行驶时,驾驶员只知道踩下油门车辆会加速,而踩下刹车车辆会停止,但不知道踩下油门时车辆的速度是怎样增加的,这就是抽象

  • 类中的抽象:我们使用可用的访问说明符对数据成员和成员函数进行分组。一个类可以决定哪个数据成员对外界可见,而哪个则不可见。
note

在头文件中也存在抽象:例如, math.h 头文件中存在的 pow() 方法。每当我们需要计算数字的幂时,我们只需调用 math.h 头文件中存在的函数 pow() 并将数字作为参数传递,而无需了解该函数实际根据其计算数字的幂的底层算法。


封装(Encapsulation)

在面向对象的编程中,封装被定义为将数据和操作它们的功能绑定在一起。

看如下代码

// Encapsulation 
#include<iostream>
using namespace std;
class Encapsulation
{
private:
int x;
public:
void set(int a)
{
x =a;
}
int get()
{
return x;
}
};
int main()
{
Encapsulation encapsulation;
encapsulation.set(0);
cout<<encapsulation.get();
return 0;
}

变量 x 被设为私有。只能使用类内部提供的 get()set() 函数来访问和操作此变量。在这里,变量 x 和函数 get()set() 绑定在一起,这就是封装

访问说明符在C ++中实现封装中起着重要作用。实现封装的过程可以分为两个步骤:

  1. 数据成员应使用私有访问说明符标记为私有
  2. 操纵数据成员的成员函数应使用公共访问说明符标记为公共
tip

封装会导致数据的抽象或隐藏


继承(Inheritance)

一个类从另一个类派生属性和特性的能力称为继承。继承是面向对象编程的最重要功能之一

  • 要从类继承,请使用 :
  • 继承概念分为两类
    • 派生类(子类)-从另一个类继承的类
    • 基类(父类)-从其继承的类

实现继承

#include <iostream>
using namespace std;
Class Student {
public:
string school = "school"
void grade(){
cout << "Grade One" <<endl;
}
}
Class Boy : public Student {
public:
string name = "boy's name"
}
int main() {
Boy boy;
boy.grade();
cout << boy.school + " " + boy.name << endl;
return 0;
}

类可以多级继承

Class BoyHobby : public Boy {
public:
string hobby = "Interested in code"
}
int main() {
BoyHobby boy;
boy.grade();
cout << boy.school + " " + boy.name + " " + boy.hobby<< endl;
return 0;
}

一个类可以由多个基类派生而来

class IDcard: public Student, public Boy, public BoyHobby {
// Code
};

多态(Polymorphism)

我们可以将多态定义为消息以多种形式显示的能力。

  • 一个人可以同时具有不同的特征。例如一个男人,是父亲,丈夫,工人。因此,同一个人在不同情况下具有不同的行为。这称为多态。
  • 一个操作在不同情况下可能表现出不同的行为。行为取决于操作中使用的数据类型
  • 多态被广泛用于实现继承

C++中多态性的两种类型

编译时多态:这种多态性是通过函数重载或运算符重载来实现的

编译时就确定了多态性 —— 静态多态

  1. 运算符重载:C++提供了重载运算符的选项
  • 假设有两个复数 10 + 5i2 + 4i,求它们的和,可如下实现
#include<iostream> 
using namespace std;
class Complex {
private:
int real_part, imaginary_part;
public:
Complex(int r = 0, int i =0){
real_part = r;
imaginary_part = i;
}
Complex operator + (Complex const &obj) {
Complex res;
res.real_part = real_part + obj.real_part;
res.imaginary_part = imaginary_part + obj.imaginary_part;
return res;
}
void print() {
cout << real_part << " + " << imaginary_part<<"i"<< endl;
}
};
int main()
{
Complex complex1(10, 5), complex2(2, 4);
Complex complex3 = complex1 + complex2;
c3.print();
}
  • 运算符 '+' 是加法运算符,但是可以通过重载来实现两个复数之间的相加
  1. 函数重载:如果有多个具有相同名称但参数不同的函数,则称这些函数为重载。可以通过更改参数数量和更改参数类型来重载函数
#include <bits/stdc++.h> 
using namespace std;
class Example {
public:
void func(int x) {
cout << "value of x is " << x << endl;
}
void func(double x) {
cout << "value of x is " << x << endl;
}
void func(int x, int y) {
cout << "value of x and y is " << x << ", " << y << endl;
}
};
int main() {
Example example;
example.func(0);
example.func(3.14159);
example.func(100,1000);
return 0;
}
  • 名为 func 的函数在三种不同的情况下的行为不同,这就是多态的属性。

运行时多态:这种类型的多态性是通过函数覆盖实现的

运行时多态主要是指在程序运行的时候,动态绑定所调用的函数,动态地找到了调用函数的入口地址,从而确定到底调用哪个函数。—— 动态多态

  • 在C++中,运行期多态主要通过虚函数来实现,并且一定要有继承关系
  • 这篇 文章中进行了补充
  • 看代码实现
#include <iostream>
using namespace std;
class parent {
public:
parent() {}
// 父类中定义的虚函数
virtual void eat() {
cout << "Parent eat." << endl;
}
// 非虚函数
void drink() {
cout << "Parent drink." << endl;
}
};
class child : public parent
{
public:
child () {}
// 子类重写了父类的虚函数
void eat() {
cout << "Child eat." << endl;
}
// 子类覆盖了父类的函数
void drink() {
cout << "Child drink." << endl;
}
// 父类没有的函数
void childLove() {
cout << "Child love playing." << endl;
}
};
int main()
{
parent* pa = new child();
pa->eat(); // 体现了运行时多态
pa->drink();
// pa->childLove(); // 父类的指针不能调用父类没有的函数
return 0;
}
  • 最后输出结果
Child eat.
Parent drink.