引言
从抽象起就算是正式接触模块化编程了。
抽象的定义
抽象是指在程序中只向外界提供关键信息,而隐藏后台的实现细节,即只表现必要的信息而不呈现细节。
就 C++ 编程而言,C++ 类为数据抽象提供了可能。它们向外界提供了大量用于操作对象数据的公共方法,也就是说,外界实际上并不清楚类的内部实现。
在 C++ 中,我们使用类来定义我们自己的抽象数据类型(ADT)。简单的说,我们使用类iostream的cout来打印文本信息,但实际上我们并不知道是怎么实现在屏幕上打印相关信息的。
封装的定义
所有的 C++ 程序都有以下两个基本要素:
- 程序语句(代码):这是程序中执行动作的部分,它们被称为函数。
- 程序数据:数据是程序的信息,会受到程序函数的影响。
封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据隐藏。
简单来说:数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。
一,理解引言部分
从上面看到这里,是不是有点晕了,因为我也不知道这样的一段话说的到底是什么,只是原封不动的把书本上的话摘抄了下来,那么我们就用大白话来理解一下这段非人类语言吧:
1️⃣数据抽象
所谓数据抽象,其实就是找出共性。比如,手机店由很多牌子的手机,由小米、华为、vivo、oppo、、金立等等等等,我们通过抽象,归纳出这些手机的共性:他们都是智能机。智能机就相当于是一个接口。
同时数据抽象会暴露接口,同时隐藏实现细节,我们回到刚才的手机话题,这些手机都是智能机,但为什么有的手机能卖8000有的手机却充话费就可以送呢?这就是在于内部细节的不同,但这些内部细节我们凭肉眼是看不到的,因此诸如主板、处理器、基带、内存这类的细节就被隐藏了。
先来看一下数据抽象的实例:
C++ 程序中,任何带有公有和私有成员的类都可以作为数据抽象的实例。
#include
using namespace std;
class Adder{
public:
// 构造函数
Adder(int i = 0)
{
total = i;
}
// 对外的接口
void addNum(int number)
{
total += number;
}
// 对外的接口
int getTotal()
{
return total;
};
private:
// 对外隐藏的数据
int total;
};
int main( )
{
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout << "Total " << a.getTotal() <
输出结果:
上面的类把数字相加,并返回总和。公有成员 addNum 和 getTotal 是对外的接口,用户需要知道它们以便使用类。私有成员 total 是用户不需要了解的,但又是类能正常工作所必需的。
2️⃣数据封装
那么什么又是数据封装呢?。
C++ 通过创建类来支持封装和数据隐藏(public、protected、private)。我们已经知道,类包含私有成员(private)、保护成员(protected)和公有成员(public)成员。默认情况下,在类中定义的所有项目都是私有的。例如:
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
变量 length、breadth 和 height 都是私有的(private)。这意味着它们只能被 Box 类中的其他成员访问,而不能被程序中其他部分访问。这是实现封装的一种方式。
为了使类中的成员变成公有的(即,程序中的其他部分也能访问),必须在这些成员前使用 public 关键字进行声明。所有定义在 public 标识符后边的变量或函数可以被程序中所有其他的函数访问。
把一个类定义为另一个类的友元类,会暴露实现细节,从而降低了封装性。理想的做法是尽可能地对外隐藏每个类的实现细节。
相关知识点:
C++中, 虚函数可以为private, 并且可以被子类覆盖(因为虚函数表的传递),但子类不能调用父类的private虚函数。虚函数的重载性和它声明的权限无关。
一个成员函数被定义为private属性,标志着其只能被当前类的其他成员函数(或友元函数)所访问。
而virtual修饰符则强调父类的成员函数可以在子类中被重写,因为重写之时并没有与父类发生任何的调用关系,故而重写是被允许的。
纯虚函数可以设计成私有的,不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有覆盖这种纯虚函数的义务,却没有调用它的权利。
参考博文:C++ 数据封装 | 菜鸟教程 (runoob.com)