Bootstrap

C++ 中类(class)和结构体(struct)的区别

在 C++ 中,**类(class)结构体(struct)**经常被用来定义复杂的数据结构,但两者之间既有区别又能很好地结合使用。本文将深入讲解它们的区别、关系,并通过丰富的代码案例说明如何灵活运用它们。
在这里插入图片描述


1. 类与结构体的核心区别

1.1 语法上的区别
  • 默认访问权限:
    • 结构体(struct): 默认访问权限是 public
    • 类(class): 默认访问权限是 private
  • 这是两者在语法上的唯一区别,但在功能上它们可以互相替代。
1.2 使用场景的区别
  • 结构体:
    更适合存储简单的数据,没有复杂行为逻辑。
  • 类:
    不仅可以存储数据,还可以定义操作行为,并支持面向对象特性,如封装、继承、多态等。
1.3 概念上的区别
  • 结构体: 偏向于“数据的集合”,是一种轻量级的数据封装工具。
  • 类: 偏向于“数据与行为的结合体”,是面向对象编程(OOP)的核心。

2. 为什么要从结构体扩展到类?

在 C 中,结构体只能存储数据,无法定义与数据相关的操作。这种方式虽然简单,但对于复杂的系统,数据和操作的分离使得代码难以维护。
C++ 引入了类(class),在继承结构体优点的基础上,增加了以下功能:

  • 支持将“数据”和“操作”封装在一起。
  • 提供访问控制(public、private、protected)。
  • 支持继承和多态,实现代码复用和扩展。

3. 类和结构体的关系

在 C++ 中,类和结构体可以看作是同源不同职

  • 同源: 类和结构体在语法和功能上几乎完全一致,都可以包含数据成员和成员函数。
  • 不同职: 结构体主要用于简单数据封装,类则更偏向于复杂逻辑实现
如何搭配使用?
  1. 结构体负责存储数据。
  2. 类负责封装行为和操作逻辑。
  3. 两者结合可以实现高效的代码组织方式。

4. 代码案例:类与结构体的结合使用

4.1 一个简单的案例:矩形面积计算

我们通过一个例子来说明如何将结构体和类结合使用。

#include <iostream>
using namespace std;

// 定义一个结构体,用来存储矩形的宽和高
struct Dimensions {
    double width;
    double height;
};

// 定义一个类,用来操作矩形
class Rectangle {
private:
    Dimensions dims;  // 使用结构体存储矩形的基本信息

public:
    // 构造函数,初始化矩形
    Rectangle(double width, double height) {
        dims.width = width;
        dims.height = height;
    }

    // 设置矩形的宽度和高度
    void setDimensions(double width, double height) {
        dims.width = width;
        dims.height = height;
    }

    // 计算矩形的面积
    double calculateArea() const {
        return dims.width * dims.height;
    }

    // 显示矩形的信息
    void display() const {
        cout << "Width: " << dims.width 
             << ", Height: " << dims.height 
             << ", Area: " << calculateArea() 
             << endl;
    }
};

int main() {
    // 创建一个矩形对象
    Rectangle rect(5.0, 10.0);

    // 显示矩形信息
    rect.display();

    // 修改矩形的尺寸
    rect.setDimensions(8.0, 12.0);

    // 再次显示矩形信息
    rect.display();

    return 0;
}
输出结果:
Width: 5, Height: 10, Area: 50
Width: 8, Height: 12, Area: 96

分析:

  • 结构体 Dimensions 负责存储矩形的宽度和高度。
  • Rectangle 负责操作矩形,比如设置尺寸和计算面积。

4.2 扩展案例:支持圆形和矩形的面积计算

进一步扩展,假设我们需要支持矩形和圆形的面积计算,可以通过继承和多态来实现。

#include <iostream>
#include <cmath>
using namespace std;

// 定义一个结构体,用来存储形状的基本属性
struct ShapeDimensions {
    double width;   // 对于矩形表示宽度
    double height;  // 对于矩形表示高度
    double radius;  // 对于圆形表示半径
};

// 定义一个基类,表示通用形状
class Shape {
protected:
    ShapeDimensions dims;

public:
    virtual double calculateArea() const = 0;  // 纯虚函数,子类必须实现
    virtual void display() const = 0;          // 纯虚函数,用于显示信息
};

// 定义矩形类,继承 Shape
class Rectangle : public Shape {
public:
    Rectangle(double width, double height) {
        dims.width = width;
        dims.height = height;
    }

    double calculateArea() const override {
        return dims.width * dims.height;
    }

    void display() const override {
        cout << "Rectangle: Width = " << dims.width 
             << ", Height = " << dims.height 
             << ", Area = " << calculateArea() 
             << endl;
    }
};

// 定义圆形类,继承 Shape
class Circle : public Shape {
public:
    Circle(double radius) {
        dims.radius = radius;
    }

    double calculateArea() const override {
        return M_PI * dims.radius * dims.radius;
    }

    void display() const override {
        cout << "Circle: Radius = " << dims.radius 
             << ", Area = " << calculateArea() 
             << endl;
    }
};

int main() {
    // 创建矩形和圆形对象
    Rectangle rect(5.0, 10.0);
    Circle circle(7.0);

    // 显示它们的面积
    rect.display();
    circle.display();

    return 0;
}
输出结果:
Rectangle: Width = 5, Height = 10, Area = 50
Circle: Radius = 7, Area = 153.938

分析:

  • 结构体 ShapeDimensions 存储矩形的宽高和圆形的半径。
  • 基类 Shape 定义通用接口(如 calculateAreadisplay)。
  • 派生类 RectangleCircle 实现特定形状的逻辑。

5. 类与结构体结合使用的总结

5.1 类和结构体的分工:
  • 结构体(struct):
    用于存储数据,结构简单,效率高。适合作为类的内部成员,用于表示数据。
  • 类(class):
    用于封装逻辑,提供操作和行为接口。适合作为更高级的抽象工具。
5.2 使用建议:
  1. 如果只是需要存储数据而没有逻辑,用结构体。
  2. 如果需要对数据进行操作或扩展功能,用类。
  3. 在复杂系统中,结构体和类结合使用可以提高代码的清晰度和可维护性。
5.3 结构体和类的关系:

它们可以看作是工具箱中的不同工具:

  • 结构体是“材料”,用于存放原始数据。
  • 类是“机器”,用于处理这些数据。

通过类与结构体的结合,我们可以在代码中清晰地分离数据和逻辑,既保持程序的简洁性,又能灵活扩展功能。

;