结构体(struct)是 C++ 中用于组织相关数据的复合数据类型。它允许将不同类型的变量组合在一起,形成一个新的数据类型。

结构体的基本概念

结构体的定义

#include <iostream>
#include <string>
 
// 基本结构体定义
struct Point {
    int x;
    int y;
};
 
// 带有不同数据类型的结构体
struct Student {
    int id;
    std::string name;
    double gpa;
    bool isActive;
};
 
// 嵌套结构体
struct Address {
    std::string street;
    std::string city;
    std::string zipCode;
};
 
struct Person {
    std::string name;
    int age;
    Address address;  // 嵌套结构体
};
 
int main() {
    std::cout << "=== 结构体基本定义 ===" << std::endl;
    
    // 显示结构体大小
    std::cout << "Point 大小: " << sizeof(Point) << " 字节" << std::endl;
    std::cout << "Student 大小: " << sizeof(Student) << " 字节" << std::endl;
    std::cout << "Person 大小: " << sizeof(Person) << " 字节" << std::endl;
    
    return 0;
}

结构体的初始化

#include <iostream>
#include <string>
 
struct Rectangle {
    double width;
    double height;
    std::string color;
};
 
struct Circle {
    double radius;
    double centerX;
    double centerY;
};
 
int main() {
    std::cout << "=== 结构体初始化方式 ===" << std::endl;
    
    // 1. 默认初始化(可能包含垃圾值)
    Rectangle rect1;
    std::cout << "默认初始化 rect1.width: " << rect1.width << std::endl;
    
    // 2. 聚合初始化(C++98)
    Rectangle rect2 = {10.5, 20.3, "red"};
    std::cout << "聚合初始化: " << rect2.width << "x" << rect2.height 
              << ", 颜色: " << rect2.color << std::endl;
    
    // 3. 部分初始化
    Rectangle rect3 = {15.0, 25.0};  // color 将被默认初始化
    std::cout << "部分初始化: " << rect3.width << "x" << rect3.height 
              << ", 颜色: '" << rect3.color << "'" << std::endl;
    
    // 4. C++11 统一初始化
    Rectangle rect4{12.0, 18.0, "blue"};
    Circle circle1{5.0, 10.0, 15.0};
    
    std::cout << "统一初始化 rect4: " << rect4.width << "x" << rect4.height 
              << ", 颜色: " << rect4.color << std::endl;
    std::cout << "统一初始化 circle1: 半径=" << circle1.radius 
              << ", 中心=(" << circle1.centerX << "," << circle1.centerY << ")" << std::endl;
    
    // 5. 指定初始化器(C++20)
    Rectangle rect5{.width = 8.0, .height = 12.0, .color = "green"};
    std::cout << "指定初始化 rect5: " << rect5.width << "x" << rect5.height 
              << ", 颜色: " << rect5.color << std::endl;
    
    // 6. 拷贝初始化
    Rectangle rect6 = rect2;
    std::cout << "拷贝初始化 rect6: " << rect6.width << "x" << rect6.height 
              << ", 颜色: " << rect6.color << std::endl;
    
    return 0;
}

结构体成员访问

基本成员访问

#include <iostream>
#include <string>
 
struct Book {
    std::string title;
    std::string author;
    int pages;
    double price;
    bool isAvailable;
};
 
void printBook(const Book& book) {
    std::cout << "书名: " << book.title << std::endl;
    std::cout << "作者: " << book.author << std::endl;
    std::cout << "页数: " << book.pages << std::endl;
    std::cout << "价格: $" << book.price << std::endl;
    std::cout << "可借阅: " << (book.isAvailable ? "是" : "否") << std::endl;
}
 
int main() {
    std::cout << "=== 结构体成员访问 ===" << std::endl;
    
    // 创建结构体实例
    Book book1 = {"C++ Primer", "Stanley Lippman", 976, 59.99, true};
    
    // 1. 直接访问成员
    std::cout << "直接访问 - 书名: " << book1.title << std::endl;
    
    // 2. 修改成员
    book1.price = 49.99;
    book1.isAvailable = false;
    
    std::cout << "\n修改后的书籍信息:" << std::endl;
    printBook(book1);
    
    // 3. 通过指针访问
    Book* bookPtr = &book1;
    std::cout << "\n通过指针访问:" << std::endl;
    std::cout << "书名: " << bookPtr->title << std::endl;
    std::cout << "价格: $" << (*bookPtr).price << std::endl;  // 等价写法
    
    // 4. 修改通过指针
    bookPtr->pages = 1000;
    bookPtr->isAvailable = true;
    
    std::cout << "\n通过指针修改后:" << std::endl;
    printBook(*bookPtr);
    
    return 0;
}

结构体数组

#include <iostream>
#include <string>
 
struct Employee {
    int id;
    std::string name;
    std::string department;
    double salary;
};
 
void printEmployee(const Employee& emp) {
    std::cout << "ID: " << emp.id 
              << ", 姓名: " << emp.name 
              << ", 部门: " << emp.department 
              << ", 薪资: $" << emp.salary << std::endl;
}
 
int main() {
    std::cout << "=== 结构体数组 ===" << std::endl;
    
    // 1. 结构体数组初始化
    Employee employees[3] = {
        {1001, "张三", "开发部", 8000.0},
        {1002, "李四", "测试部", 7000.0},
        {1003, "王五", "产品部", 9000.0}
    };
    
    // 2. 遍历结构体数组
    std::cout << "所有员工信息:" << std::endl;
    for (int i = 0; i < 3; ++i) {
        printEmployee(employees[i]);
    }
    
    // 3. 修改数组中的结构体
    employees[1].salary = 7500.0;
    employees[1].department = "高级测试部";
    
    std::cout << "\n修改后的员工信息:" << std::endl;
    for (const auto& emp : employees) {  // C++11 范围for循环
        printEmployee(emp);
    }
    
    // 4. 查找特定员工
    std::string searchName = "王五";
    Employee* found = nullptr;
    
    for (int i = 0; i < 3; ++i) {
        if (employees[i].name == searchName) {
            found = &employees[i];
            break;
        }
    }
    
    if (found) {
        std::cout << "\n找到员工: ";
        printEmployee(*found);
    } else {
        std::cout << "\n未找到员工: " << searchName << std::endl;
    }
    
    return 0;
}

结构体与函数

结构体作为函数参数

#include <iostream>
#include <string>
#include <cmath>
 
struct Point3D {
    double x, y, z;
};
 
struct Vector3D {
    double x, y, z;
};
 
// 1. 传值方式(会拷贝整个结构体)
double calculateDistance(Point3D p1, Point3D p2) {
    double dx = p2.x - p1.x;
    double dy = p2.y - p1.y;
    double dz = p2.z - p1.z;
    return std::sqrt(dx*dx + dy*dy + dz*dz);
}
 
// 2. 传引用方式(推荐,避免拷贝)
double calculateDistanceRef(const Point3D& p1, const Point3D& p2) {
    double dx = p2.x - p1.x;
    double dy = p2.y - p1.y;
    double dz = p2.z - p1.z;
    return std::sqrt(dx*dx + dy*dy + dz*dz);
}
 
// 3. 传指针方式
double calculateDistancePtr(const Point3D* p1, const Point3D* p2) {
    if (!p1 || !p2) return 0.0;
    
    double dx = p2->x - p1->x;
    double dy = p2->y - p1->y;
    double dz = p2->z - p1->z;
    return std::sqrt(dx*dx + dy*dy + dz*dz);
}
 
// 4. 修改结构体的函数
void movePoint(Point3D& point, const Vector3D& vector) {
    point.x += vector.x;
    point.y += vector.y;
    point.z += vector.z;
}
 
// 5. 返回结构体的函数
Point3D createPoint(double x, double y, double z) {
    return {x, y, z};  // C++11 返回列表初始化
}
 
Vector3D calculateVector(const Point3D& from, const Point3D& to) {
    return {to.x - from.x, to.y - from.y, to.z - from.z};
}
 
void printPoint(const Point3D& p) {
    std::cout << "(" << p.x << ", " << p.y << ", " << p.z << ")";
}
 
int main() {
    std::cout << "=== 结构体与函数 ===" << std::endl;
    
    // 创建点
    Point3D origin = {0.0, 0.0, 0.0};
    Point3D point1 = createPoint(3.0, 4.0, 5.0);
    Point3D point2 = {6.0, 8.0, 10.0};
    
    std::cout << "原点: ";
    printPoint(origin);
    std::cout << std::endl;
    
    std::cout << "点1: ";
    printPoint(point1);
    std::cout << std::endl;
    
    std::cout << "点2: ";
    printPoint(point2);
    std::cout << std::endl;
    
    // 计算距离
    double dist1 = calculateDistance(origin, point1);
    double dist2 = calculateDistanceRef(point1, point2);
    double dist3 = calculateDistancePtr(&origin, &point2);
    
    std::cout << "\n距离计算:" << std::endl;
    std::cout << "原点到点1的距离: " << dist1 << std::endl;
    std::cout << "点1到点2的距离: " << dist2 << std::endl;
    std::cout << "原点到点2的距离: " << dist3 << std::endl;
    
    // 移动点
    Vector3D moveVector = calculateVector(origin, point1);
    std::cout << "\n移动向量: (" << moveVector.x << ", " 
              << moveVector.y << ", " << moveVector.z << ")" << std::endl;
    
    Point3D movingPoint = origin;
    std::cout << "移动前: ";
    printPoint(movingPoint);
    
    movePoint(movingPoint, moveVector);
    std::cout << " -> 移动后: ";
    printPoint(movingPoint);
    std::cout << std::endl;
    
    return 0;
}

结构体的高级特性

结构体中的函数(成员函数)

在C++中,结构体不仅可以包含数据成员,还可以包含成员函数。这使得结构体能够封装数据和操作数据的方法,实现面向对象编程的基本概念。

#include <iostream>
#include <string>
#include <cmath>
 
struct Circle {
    double radius;
    double centerX, centerY;
    
    // 构造函数
    Circle(double r = 1.0, double x = 0.0, double y = 0.0) 
        : radius(r), centerX(x), centerY(y) {}
    
    // 成员函数:计算面积
    double area() const {
        return M_PI * radius * radius;
    }
    
    // 成员函数:计算周长
    double circumference() const {
        return 2 * M_PI * radius;
    }
    
    // 成员函数:移动圆心
    void move(double dx, double dy) {
        centerX += dx;
        centerY += dy;
    }
    
    // 成员函数:缩放半径
    void scale(double factor) {
        if (factor > 0) {
            radius *= factor;
        }
    }
    
    // 成员函数:检查点是否在圆内
    bool contains(double x, double y) const {
        double dx = x - centerX;
        double dy = y - centerY;
        return (dx*dx + dy*dy) <= (radius*radius);
    }
    
    // 成员函数:显示信息
    void display() const {
        std::cout << "圆心: (" << centerX << ", " << centerY 
                  << "), 半径: " << radius 
                  << ", 面积: " << area() 
                  << ", 周长: " << circumference() << std::endl;
    }
    
    // 静态成员函数:比较两个圆的面积
    static bool compareArea(const Circle& c1, const Circle& c2) {
        return c1.area() > c2.area();
    }
};
 
struct Rectangle {
    double width, height;
    double x, y;  // 左下角坐标
    
    Rectangle(double w = 1.0, double h = 1.0, double px = 0.0, double py = 0.0)
        : width(w), height(h), x(px), y(py) {}
    
    double area() const {
        return width * height;
    }
    
    double perimeter() const {
        return 2 * (width + height);
    }
    
    bool contains(double px, double py) const {
        return px >= x && px <= x + width && 
               py >= y && py <= y + height;
    }
    
    void move(double dx, double dy) {
        x += dx;
        y += dy;
    }
    
    void resize(double newWidth, double newHeight) {
        if (newWidth > 0 && newHeight > 0) {
            width = newWidth;
            height = newHeight;
        }
    }
    
    void display() const {
        std::cout << "矩形: 位置(" << x << ", " << y 
                  << "), 大小(" << width << "x" << height 
                  << "), 面积: " << area() 
                  << ", 周长: " << perimeter() << std::endl;
    }
    
    // 检查是否为正方形
    bool isSquare() const {
        return std::abs(width - height) < 1e-9;
    }
};
 
// 使用示例
int main() {
    // 创建圆对象
    Circle c1(5.0, 10.0, 20.0);
    Circle c2(3.0);
    
    std::cout << "=== 圆的操作 ===" << std::endl;
    c1.display();
    c2.display();
    
    // 移动和缩放
    c1.move(5.0, -3.0);
    c1.scale(1.5);
    std::cout << "移动和缩放后:" << std::endl;
    c1.display();
    
    // 检查点是否在圆内
    std::cout << "点(15, 17)是否在圆c1内: " << (c1.contains(15, 17) ? "是" : "否") << std::endl;
    
    // 比较圆的面积
    std::cout << "c1面积是否大于c2: " << (Circle::compareArea(c1, c2) ? "是" : "否") << std::endl;
    
    std::cout << "\n=== 矩形的操作 ===" << std::endl;
    
    // 创建矩形对象
    Rectangle r1(4.0, 6.0, 2.0, 3.0);
    Rectangle r2(5.0, 5.0);  // 正方形
    
    r1.display();
    r2.display();
    
    // 检查是否为正方形
    std::cout << "r1是正方形吗: " << (r1.isSquare() ? "是" : "否") << std::endl;
    std::cout << "r2是正方形吗: " << (r2.isSquare() ? "是" : "否") << std::endl;
    
    // 移动和调整大小
    r1.move(1.0, 2.0);
    r1.resize(8.0, 4.0);
    std::cout << "移动和调整大小后:" << std::endl;
    r1.display();
    
    return 0;
}

访问控制和封装

虽然结构体默认成员是公有的,但我们也可以使用访问控制关键字来实现更好的封装:

struct BankAccount {
private:
    std::string accountNumber;
    double balance;
    static int nextAccountId;  // 静态成员变量
    
public:
    // 构造函数
    BankAccount(const std::string& owner, double initialBalance = 0.0) 
        : balance(initialBalance) {
        accountNumber = "ACC" + std::to_string(++nextAccountId);
        ownerName = owner;
    }
    
    // 公有成员
    std::string ownerName;
    
    // 存款
    bool deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            return true;
        }
        return false;
    }
    
    // 取款
    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
    
    // 查询余额
    double getBalance() const {
        return balance;
    }
    
    // 获取账号
    std::string getAccountNumber() const {
        return accountNumber;
    }
    
    // 显示账户信息
    void displayInfo() const {
        std::cout << "账户: " << accountNumber 
                  << ", 户主: " << ownerName 
                  << ", 余额: $" << balance << std::endl;
    }
    
    // 转账功能
    bool transferTo(BankAccount& target, double amount) {
        if (withdraw(amount)) {
            target.deposit(amount);
            return true;
        }
        return false;
    }
};
 
// 静态成员变量定义
int BankAccount::nextAccountId = 1000;

运算符重载

结构体还可以重载运算符,使得自定义类型的使用更加直观:

struct Point {
    double x, y;
    
    Point(double px = 0.0, double py = 0.0) : x(px), y(py) {}
    
    // 重载加法运算符
    Point operator+(const Point& other) const {
        return Point(x + other.x, y + other.y);
    }
    
    // 重载减法运算符
    Point operator-(const Point& other) const {
        return Point(x - other.x, y - other.y);
    }
    
    // 重载乘法运算符(标量乘法)
    Point operator*(double scalar) const {
        return Point(x * scalar, y * scalar);
    }
    
    // 重载相等比较运算符
    bool operator==(const Point& other) const {
        return std::abs(x - other.x) < 1e-9 && std::abs(y - other.y) < 1e-9;
    }
    
    // 重载输出流运算符(友元函数)
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << "(" << p.x << ", " << p.y << ")";
        return os;
    }
    
    // 计算到原点的距离
    double distance() const {
        return std::sqrt(x*x + y*y);
    }
    
    // 计算到另一点的距离
    double distanceTo(const Point& other) const {
        double dx = x - other.x;
        double dy = y - other.y;
        return std::sqrt(dx*dx + dy*dy);
    }
};
 
// 使用示例
void demonstrateAdvancedFeatures() {
    std::cout << "=== 银行账户示例 ===" << std::endl;
    BankAccount acc1("张三", 1000.0);
    BankAccount acc2("李四", 500.0);
    
    acc1.displayInfo();
    acc2.displayInfo();
    
    // 存取款操作
    acc1.deposit(200.0);
    acc1.withdraw(150.0);
    
    // 转账操作
    if (acc1.transferTo(acc2, 300.0)) {
        std::cout << "转账成功!" << std::endl;
    }
    
    acc1.displayInfo();
    acc2.displayInfo();
    
    std::cout << "\n=== 点运算符重载示例 ===" << std::endl;
    Point p1(3.0, 4.0);
    Point p2(1.0, 2.0);
    
    std::cout << "p1 = " << p1 << std::endl;
    std::cout << "p2 = " << p2 << std::endl;
    
    Point p3 = p1 + p2;
    Point p4 = p1 - p2;
    Point p5 = p1 * 2.0;
    
    std::cout << "p1 + p2 = " << p3 << std::endl;
    std::cout << "p1 - p2 = " << p4 << std::endl;
    std::cout << "p1 * 2 = " << p5 << std::endl;
    
    std::cout << "p1到原点距离: " << p1.distance() << std::endl;
    std::cout << "p1到p2距离: " << p1.distanceTo(p2) << std::endl;
    
    std::cout << "p1 == p2: " << (p1 == p2 ? "true" : "false") << std::endl;
}

关键概念总结

const成员函数:使用const关键字声明的成员函数承诺不会修改对象的状态,这样的函数可以被const对象调用。

构造函数:特殊的成员函数,用于初始化对象。可以有参数,支持默认参数和初始化列表。

静态成员:属于类型本身而不是特定对象的成员,所有对象共享同一份静态成员。

访问控制:通过privateprotectedpublic关键字控制成员的访问权限,实现数据封装。

运算符重载:允许为自定义类型定义运算符的行为,使代码更加直观和易读。

这些高级特性使得C++结构体具有了面向对象编程的强大功能,能够创建更加复杂和实用的数据类型。