菜鸟教程 -- 学的不仅是技术,更是梦想!

C++ 教程
C++ 教程 C++ 简介 C++ 环境设置 C++ 基本语法 C++ 注释 C++ 数据类型 C++ 变量类型 C++ 变量作用域 C++ 常量 C++ 修饰符类型 C++ 存储类 C++ 运算符 C++ 循环 C++ 判断 C++ 函数 C++ 数字 C++ 数组 C++ 字符串 C++ 指针 C++ 引用 C++ 日期 & 时间 C++ 基本的输入输出 C++ 结构体(struct) C++ vector 容器 C++ 数据结构

C++ 面向对象

C++ 类 & 对象 C++ 继承 C++ 重载运算符和重载函数 C++ 多态 C++ 数据抽象 C++ 数据封装 C++ 接口(抽象类)

C++ 高级教程

C++ 文件和流 C++ 异常处理 C++ 动态内存 C++ 命名空间 C++ 模板 C++ 预处理器 C++ 信号处理 C++ 多线程 C++ Web 编程

C++ 资源库

C++ STL 教程 C++ 导入标准库 C++ 标准库 C++ 有用的资源 C++ 实例 C++ 测验 C++ <iostream> C++ <fstream> C++ <sstream> C++ <iomanip> C++ <array> C++ <vector> C++ <list> C++ <forward_list> C++ <deque> C++ <stack> C++ <queue> C++ <priority_queue> C++ <set> C++ <unordered_set> C++ <map> C++ <unordered_map> C++ <bitset> C++ <algorithm> C++ <iterator> C++ <functional> C++ <numeric> C++ <complex> C++ <valarray> C++ <cmath> C++ <string> C++ <regex> C++ <ctime> C++ <chrono> C++ <thread> C++ <mutex> C++ <condition_variable> C++ <future> C++ <atomic> C++ <type_traits> C++ <typeinfo> C++ <exception> C++ <stdexcept> C++ <cstdio> C++ <cstdint> C++ <memory> C++ <new> C++ <utility> C++ <random> C++ <locale> C++ <codecvt> C++ <cassert> C++ <cwchar> C++ <climits> C++ <cfloat> C++ <cstdlib> C++ <numbers> C++ OpenCV
(追記) (追記ここまで)

C++ 数据封装

数据封装(Data Encapsulation)是面向对象编程(OOP)的一个基本概念,它通过将数据和操作数据的函数封装在一个类中来实现。这种封装确保了数据的私有性和完整性,防止了外部代码对其直接访问和修改。

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

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

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

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

C++ 通过创建来支持封装和数据隐藏(public、protected、private)。我们已经知道,类包含私有成员(private)、保护成员(protected)和公有成员(public)成员。默认情况下,在类中定义的所有项目都是私有的。例如:

classBox{public: doublegetVolume(void){returnlength * breadth * height; }private: doublelength; // 长度doublebreadth; // 宽度doubleheight; // 高度};

变量 length、breadth 和 height 都是私有的(private)。这意味着它们只能被 Box 类中的其他成员访问,而不能被程序中其他部分访问。这是实现封装的一种方式。

为了使类中的成员变成公有的(即,程序中的其他部分也能访问),必须在这些成员前使用 public 关键字进行声明。所有定义在 public 标识符后边的变量或函数可以被程序中所有其他的函数访问。

把一个类定义为另一个类的友元类,会暴露实现细节,从而降低了封装性。理想的做法是尽可能地对外隐藏每个类的实现细节。

访问修饰符:

  • private: 私有成员只能在类的内部访问,不能被类的外部代码直接访问。
  • public: 公有成员可以被类的外部代码直接访问。
  • protected: 受保护成员可以被类和其派生类访问。

数据封装的实例

C++ 程序中,任何带有公有和私有成员的类都可以作为数据封装和数据抽象的实例。请看下面的实例:

实例

#include<iostream>usingnamespacestd; classAdder{public: // 构造函数Adder(inti = 0){total = i; }// 对外的接口voidaddNum(intnumber){total += number; }// 对外的接口intgetTotal(){returntotal; }; private: // 对外隐藏的数据inttotal; }; intmain(){Addera; a.addNum(10); a.addNum(20); a.addNum(30); cout << "Total " << a.getTotal() <<endl; return0; }

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

Total 60

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

数据封装通过类和访问修饰符(public, private, protected)来实现,以下是一个简单的例子:

实例

#include <iostream>
using namespace std;

class Student {
private:
string name;
int age;

public:
// 构造函数
Student(string studentName, int studentAge) {
name = studentName;
age = studentAge;
}

// 访问器函数(getter)
string getName() {
return name;
}

int getAge() {
return age;
}

// 修改器函数(setter)
void setName(string studentName) {
name = studentName;
}

void setAge(int studentAge) {
if (studentAge > 0) {
age = studentAge;
} else {
cout << "Invalid age!" << endl;
}
}

// 打印学生信息
void printInfo() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};

int main() {
// 创建一个 Student 对象
Student student1("Alice", 20);

// 访问和修改数据
student1.printInfo();

student1.setName("Bob");
student1.setAge(22);

student1.printInfo();

return 0;
}

设计策略

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

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

数据封装的优点

  • 数据隐藏: 通过将数据成员声明为私有,防止外部代码直接访问这些数据。
  • 提高代码可维护性: 提供公共方法来访问和修改数据,这使得可以在不影响外部代码的情况下修改类的内部实现。
  • 增强安全性: 防止不合法的数据输入和不当的修改操作。
  • 实现抽象: 提供了一种机制,使得用户不需要了解类的内部实现细节,只需要了解如何使用类的公共接口即可。
AI 思考中...

2 篇笔记 写笔记

  1. #0
    856

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

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

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

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

    7年前 (2019年03月11日)
  2. #0
    55

    数据封装和数据抽象概念的区别

    关注点不同:

    • 封装关注的是数据和操作方法的绑定,以及对外部访问的控制。
    • 抽象关注的是简化复杂性,通过隐藏实现细节来只暴露对象的主要特性和功能。

    实现方式:

    • 封装通过访问控制(如 privateprotectedpublic 访问修饰符)实现。
    • 抽象通过抽象类和接口(纯虚函数等)实现。

    目的:

    • 封装主要是为了数据保护和隐藏实现细节。
    • 抽象主要是为了简化复杂性和提高代码的可读性与可维护性。

    侧重点:

    • 封装侧重于对象内部的设计,通过隐藏数据和提供访问方法来保护对象的内部状态。
    • 抽象侧重于对象对外的接口设计,通过提供简化的接口来隐藏复杂的实现细节。
    2年前 (2024年07月01日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /