结构体(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对象调用。
构造函数:特殊的成员函数,用于初始化对象。可以有参数,支持默认参数和初始化列表。
静态成员:属于类型本身而不是特定对象的成员,所有对象共享同一份静态成员。
访问控制:通过private
、protected
、public
关键字控制成员的访问权限,实现数据封装。
运算符重载:允许为自定义类型定义运算符的行为,使代码更加直观和易读。
这些高级特性使得C++结构体具有了面向对象编程的强大功能,能够创建更加复杂和实用的数据类型。