C++ 面向对象(6)——C++ 数据封装

news/2024/12/5 8:11:25/

所有的 C++ 程序都有以下两个基本要素:

  • 程序语句(代码):这是程序中执行动作的部分,它们被称为函数。
  • 程序数据:数据是程序的信息,会受到程序函数的影响。

封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据隐藏

数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。

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++ 程序中,任何带有公有和私有成员的类都可以作为数据封装和数据抽象的实例。请看下面的实例:

实例

#include <iostream>

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() <<endl;

return 0;

}

当上面的代码被编译和执行时,它会产生下列结果:

Total 60

上面的类把数字相加,并返回总和。公有成员 addNum 和 getTotal 是对外的接口,用户需要知道它们以便使用类。私有成员 total 是对外隐藏的,用户不需要了解它,但它又是类能正常工作所必需的。

设计策略

通常情况下,我们都会设置类成员状态为私有(private),除非我们真的需要将其暴露,这样才能保证良好的封装性

这通常应用于数据成员,但它同样适用于所有成员,包括虚函数。

补充知识:

C++中, 虚函数可以为private, 并且可以被子类覆盖(因为虚函数表的传递),但子类不能调用父类的private虚函数。虚函数的重载性和它声明的权限无关。

一个成员函数被定义为private属性,标志着其只能被当前类的其他成员函数(或友元函数)所访问。而virtual修饰符则强调父类的成员函数可以在子类中被重写,因为重写之时并没有与父类发生任何的调用关系,故而重写是被允许的。

编译器不检查虚函数的各类属性。被virtual修饰的成员函数,不论他们是private、protect或是public的,都会被统一的放置到虚函数表中。对父类进行派生时,子类会继承到拥有相同偏移地址的虚函数表(相同偏移地址指,各虚函数相对于VPTR指针的偏移),则子类就会被允许对这些虚函数进行重载。且重载时可以给重载函数定义新的属性,例如public,其只标志着该重载函数在该子类中的访问属性为public,和父类的private属性没有任何关系!

纯虚函数可以设计成私有的,不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有覆盖这种纯虚函数的义务,却没有调用它的权利。


http://www.ppmy.cn/news/583391.html

相关文章

Laravel 复杂的查询

Laravel提供了强大的查询构建器&#xff08;Query Builder&#xff09;和Eloquent ORM来处理复杂的数据库查询。下面是一些示例展示如何在Laravel中执行复杂查询&#xff1a; 1. 基本查询&#xff1a; php $users DB::table(users)->get(); // 获取所有用户 $user DB::tab…

Windows下安装ClickHouse图文教程

文章目录 1.安装WSL21.1启用适用于 Linux 的 Windows 子系统1.2启用Windows虚拟机功能1.3将WSL2设置为默认版本1.4下载Linux内核更新包1.5安装Linux子系统1.6设置账户和密码 2.安装Docker2.1下载与安装2.2设置镜像地址 3.安装Clickhouse3.1拉取镜像3.2启动clickhouse-server3.3…

leetcode数据库题第八弹(免费题刷完了)

leetcode数据库题第八弹&#xff08;免费题刷完了&#xff09; 1757. 可回收且低脂的产品1789. 员工的直属部门1795. 每个产品在不同商店的价格1873. 计算特殊奖金1890. 2020年最后一次登录1907. 按分类统计薪水1934. 确认率1965. 丢失信息的雇员1978. 上级经理已离职的公司员工…

DataWhale-动手数据分析-Task01:数据加载及探索性数据分析

part1 &#xff1a;数据加载1.1 载入数据1.1.1 任务一&#xff1a;导入numpy和pandas1.1.2 任务二&#xff1a;载入数据【提示1】相对路径载入报错时&#xff0c;尝试使用os.getcwd()查看当前工作目录。【思考2】知道数据加载的方法后&#xff0c;试试pd.read_csv()和pd.read_t…

HDFS写流程源码分析(二)-NameNode服务端

HDFS 写流程源码分析 一、客户端二、NameNode端&#xff08;一&#xff09;create&#xff08;二&#xff09;addBlock&#xff08;三&#xff09;complete 三、DataNode端 环境为hadoop 3.1.3 一、客户端 HDFS写流程源码分析&#xff08;一&#xff09;-客户端 二、NameNode…

neon浮点运算_NEON简单介绍

“ARM Advanced SIMD”,nick-named “NEON”, it provides:(1)、A set of interesting scalar/vectorinstructions and registers(the latter are mapped to the same chip area as theFPU ones), comparable to MMX/SSE/3DNow! in the 86 world;(2)、VFPv3-D32 as a requireme…

Learning to detect open classes for universal domain adaption

摘要 UDA转移域间知识&#xff0c;不需标签集的任何限制&#xff0c;扩展了域适应的可用性。UDA中&#xff0c;源、目标标签集可能具有单独的标签不被另一个域共享。UDA挑战&#xff1a;对抗域偏移&#xff0c;分类共享类中的目标样本&#xff0c;更突出的&#xff1a;将单独的…

Datawhale- DS- Jun - 第一章:第一节数据载入及初步观察-课程

**复习&#xff1a;**这门课程得主要目的是通过真实的数据&#xff0c;以实战的方式了解数据分析的流程和熟悉数据分析python的基本操作。知道了课程的目的之后&#xff0c;我们接下来我们要正式的开始数据分析的实战教学&#xff0c;完成kaggle上泰坦尼克的任务&#xff0c;实…