【C++】从零开始构建C++停车场管理系统:技术详解与实战指南

引言:为什么需要学习这个项目?

在当今数字化时代,掌握全栈开发能力 是成为优秀程序员的必经之路。今天,我将带领大家从零开始构建一个完整的停车场管理系统。这个项目不仅涵盖了C++核心编程MySQL数据库操作软件架构设计 等关键技术,更是一个绝佳的综合练习项目,适合有一定C++基础想提升实战能力的开发者。

一、项目概述与技术栈

1.1 项目功能亮点

  • 🚗 智能车辆管理:入场登记、出场结算、停车查询

  • 💰 灵活计费系统:支持小时计费、月卡会员、优惠折扣

  • 📊 实时数据监控:车位状态、收入统计、使用率分析

  • 🔐 多用户系统:管理员与操作员分级权限

1.2 技术栈详解

cpp 复制代码
// 技术栈构成
- 核心语言: C++11/14 (现代C++特性)
- 数据库: MySQL 8.0 (关系型数据库)
- 连接驱动: MySQL Connector/C++ (官方库)
- 开发环境: VS2019 (Windows) / GCC (Linux)
- 设计模式: 单例模式、工厂模式、策略模式

二、环境配置:一步一图详细教程

2.1 Windows环境配置(VS2019)

步骤1:安装MySQL数据库
bash 复制代码
# 1. 访问MySQL官网下载安装包
# 2. 选择MySQL Installer for Windows
# 3. 安装时记住设置的root密码(如:123456)
# 4. 确保MySQL服务已启动(在服务中查看)
步骤2:配置VS2019项目

打开VS2019,按以下步骤操作:

项目属性配置:

  1. 右键项目 → 属性 → VC++目录

  2. 包含目录 添加:C:\Program Files\MySQL\MySQL Connector C++ 8.0\include

  3. 库目录 添加:C:\Program Files\MySQL\MySQL Connector C++ 8.0\lib64

链接器配置:

  1. 属性 → 链接器 → 输入

  2. 附加依赖项 添加:mysqlcppconn.lib

重要:libmysql.dll复制到:

  • 项目输出目录(Debug/Release文件夹)

  • C:\Windows\System32 (64位系统)

2.2 Linux环境配置

cpp 复制代码
# Ubuntu/Debian系统
sudo apt update
sudo apt install mysql-server mysql-client
sudo apt install libmysqlcppconn-dev build-essential cmake

# 启动MySQL服务
sudo systemctl start mysql
sudo systemctl enable mysql

# 验证安装
mysql --version

三、数据库设计:初学者必懂的核心概念

3.1 数据库创建与配置

cpp 复制代码
-- 第一步:创建数据库
CREATE DATABASE IF NOT EXISTS parking_system
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

USE parking_system;

-- 第二步:创建核心表
-- 车辆信息表(核心表)
CREATE TABLE vehicles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    plate_number VARCHAR(20) NOT NULL,      -- 车牌号
    vehicle_type ENUM('小型车','中型车','大型车') DEFAULT '小型车',
    entry_time DATETIME NOT NULL,          -- 入场时间
    exit_time DATETIME,                    -- 出场时间
    parking_space INT NOT NULL,            -- 停车位
    status ENUM('parking','exited') DEFAULT 'parking',
    total_fee DECIMAL(10,2) DEFAULT 0.00,  -- 总费用
    paid_amount DECIMAL(10,2) DEFAULT 0.00 -- 已付金额
);

-- 收费记录表
CREATE TABLE payment_records (
    id INT PRIMARY KEY AUTO_INCREMENT,
    vehicle_id INT NOT NULL,
    plate_number VARCHAR(20) NOT NULL,
    payment_time DATETIME NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (vehicle_id) REFERENCES vehicles(id)
);

3.2 为什么要这样设计?

  • AUTO_INCREMENT:自动生成ID,避免重复

  • ENUM类型:限制字段取值范围,保证数据一致性

  • DATETIME:精确记录时间,便于计费计算

  • 外键约束:保证数据完整性,防止无效记录

四、核心代码实现:分模块详解

4.1 数据库连接模块

cpp 复制代码
// DatabaseHandler.h - 数据库连接核心类
#ifndef DATABASEHANDLER_H
#define DATABASEHANDLER_H

#include <mysql.h>
#include <string>
#include <iostream>

class DatabaseHandler {
private:
    MYSQL* connection;
    std::string host;
    std::string user;
    std::string password;
    std::string database;
    
    // 私有化构造函数(单例模式)
    DatabaseHandler() {
        host = "localhost";
        user = "root";
        password = "123456";  // 修改为你的密码
        database = "parking_system";
        connection = nullptr;
    }
    
public:
    // 获取单例实例
    static DatabaseHandler& getInstance() {
        static DatabaseHandler instance;
        return instance;
    }
    
    // 禁止拷贝
    DatabaseHandler(const DatabaseHandler&) = delete;
    DatabaseHandler& operator=(const DatabaseHandler&) = delete;
    
    // 连接数据库
    bool connect() {
        connection = mysql_init(nullptr);
        if (!connection) {
            std::cerr << "初始化MySQL连接失败" << std::endl;
            return false;
        }
        
        // 建立连接
        if (!mysql_real_connect(connection, host.c_str(), user.c_str(),
                               password.c_str(), database.c_str(),
                               3306, nullptr, 0)) {
            std::cerr << "连接失败: " << mysql_error(connection) << std::endl;
            return false;
        }
        
        // 设置字符集
        mysql_set_character_set(connection, "utf8");
        std::cout << "数据库连接成功!" << std::endl;
        return true;
    }
    
    // 执行查询
    MYSQL_RES* query(const std::string& sql) {
        if (mysql_query(connection, sql.c_str()) != 0) {
            std::cerr << "查询失败: " << mysql_error(connection) << std::endl;
            return nullptr;
        }
        return mysql_store_result(connection);
    }
    
    // 执行更新(插入、更新、删除)
    bool execute(const std::string& sql) {
        return mysql_query(connection, sql.c_str()) == 0;
    }
    
    // 获取最后插入的ID
    int getLastInsertId() {
        return mysql_insert_id(connection);
    }
    
    ~DatabaseHandler() {
        if (connection) {
            mysql_close(connection);
        }
    }
};

#endif // DATABASEHANDLER_H

4.2 车辆管理模块

cpp 复制代码
// VehicleManager.cpp - 车辆业务逻辑
#include "DatabaseHandler.h"
#include <sstream>
#include <iomanip>

class VehicleManager {
private:
    DatabaseHandler& db;
    
public:
    VehicleManager() : db(DatabaseHandler::getInstance()) {}
    
    // 车辆入场
    bool vehicleEntry(const std::string& plate, int space) {
        // 检查车辆是否已在场内
        std::string checkSql = "SELECT COUNT(*) FROM vehicles WHERE "
                              "plate_number = '" + plate + "' AND status = 'parking'";
        
        MYSQL_RES* result = db.query(checkSql);
        if (result) {
            MYSQL_ROW row = mysql_fetch_row(result);
            if (row && std::stoi(row[0]) > 0) {
                std::cout << "车辆已在场内!" << std::endl;
                mysql_free_result(result);
                return false;
            }
            mysql_free_result(result);
        }
        
        // 获取当前时间
        time_t now = time(nullptr);
        tm* ltm = localtime(&now);
        std::stringstream ss;
        ss << (1900 + ltm->tm_year) << "-"
           << std::setfill('0') << std::setw(2) << (1 + ltm->tm_mon) << "-"
           << std::setfill('0') << std::setw(2) << ltm->tm_mday << " "
           << std::setfill('0') << std::setw(2) << ltm->tm_hour << ":"
           << std::setfill('0') << std::setw(2) << ltm->tm_min << ":"
           << std::setfill('0') << std::setw(2) << ltm->tm_sec;
        
        std::string entryTime = ss.str();
        
        // 插入车辆记录
        std::string insertSql = "INSERT INTO vehicles (plate_number, entry_time, "
                               "parking_space, status) VALUES ('" + plate + "', '" 
                               + entryTime + "', " + std::to_string(space) + ", 'parking')";
        
        if (db.execute(insertSql)) {
            std::cout << "车辆入场成功!" << std::endl;
            std::cout << "车牌号: " << plate << std::endl;
            std::cout << "停车位: " << space << std::endl;
            std::cout << "入场时间: " << entryTime << std::endl;
            return true;
        }
        
        return false;
    }
    
    // 车辆出场
    bool vehicleExit(const std::string& plate, double hourlyRate = 5.0) {
        // 获取车辆信息
        std::string selectSql = "SELECT id, entry_time FROM vehicles WHERE "
                               "plate_number = '" + plate + "' AND status = 'parking'";
        
        MYSQL_RES* result = db.query(selectSql);
        if (!result) return false;
        
        MYSQL_ROW row = mysql_fetch_row(result);
        if (!row) {
            std::cout << "未找到该车辆的停车记录!" << std::endl;
            mysql_free_result(result);
            return false;
        }
        
        int vehicleId = std::stoi(row[0]);
        std::string entryTime = row[1];
        mysql_free_result(result);
        
        // 计算停车时长和费用
        time_t now = time(nullptr);
        tm entryTm = {}, nowTm = {};
        strptime(entryTime.c_str(), "%Y-%m-%d %H:%M:%S", &entryTm);
        localtime_r(&now, &nowTm);
        
        double hours = difftime(now, mktime(&entryTm)) / 3600.0;
        double fee = hours * hourlyRate;
        
        // 获取当前时间作为出场时间
        std::stringstream ss;
        ss << (1900 + nowTm.tm_year) << "-"
           << std::setfill('0') << std::setw(2) << (1 + nowTm.tm_mon) << "-"
           << std::setfill('0') << std::setw(2) << nowTm.tm_mday << " "
           << std::setfill('0') << std::setw(2) << nowTm.tm_hour << ":"
           << std::setfill('0') << std::setw(2) << nowTm.tm_min << ":"
           << std::setfill('0') << std::setw(2) << nowTm.tm_sec;
        
        std::string exitTime = ss.str();
        
        // 更新车辆记录
        std::string updateSql = "UPDATE vehicles SET exit_time = '" + exitTime + 
                               "', total_fee = " + std::to_string(fee) + 
                               ", status = 'exited' WHERE id = " + std::to_string(vehicleId);
        
        if (db.execute(updateSql)) {
            // 添加收费记录
            std::string paymentSql = "INSERT INTO payment_records (vehicle_id, plate_number, "
                                    "payment_time, amount) VALUES (" + std::to_string(vehicleId) + 
                                    ", '" + plate + "', '" + exitTime + "', " + 
                                    std::to_string(fee) + ")";
            
            db.execute(paymentSql);
            
            std::cout << "\n=== 收费详情 ===" << std::endl;
            std::cout << "车牌号: " << plate << std::endl;
            std::cout << "入场时间: " << entryTime << std::endl;
            std::cout << "出场时间: " << exitTime << std::endl;
            std::cout << "停车时长: " << std::fixed << std::setprecision(2) 
                     << hours << "小时" << std::endl;
            std::cout << "停车费用: " << fee << "元" << std::endl;
            
            return true;
        }
        
        return false;
    }
    
    // 查询停放中车辆
    void showParkingVehicles() {
        std::string sql = "SELECT plate_number, vehicle_type, entry_time, "
                         "parking_space FROM vehicles WHERE status = 'parking'";
        
        MYSQL_RES* result = db.query(sql);
        if (!result) return;
        
        std::cout << "\n=== 停放中车辆列表 ===" << std::endl;
        std::cout << std::left << std::setw(15) << "车牌号"
                  << std::setw(10) << "车型"
                  << std::setw(20) << "入场时间"
                  << std::setw(10) << "停车位" << std::endl;
        
        MYSQL_ROW row;
        while ((row = mysql_fetch_row(result))) {
            std::cout << std::left << std::setw(15) << (row[0] ? row[0] : "")
                      << std::setw(10) << (row[1] ? row[1] : "")
                      << std::setw(20) << (row[2] ? row[2] : "")
                      << std::setw(10) << (row[3] ? row[3] : "") << std::endl;
        }
        
        mysql_free_result(result);
    }
};

4.3 用户界面模块

cpp 复制代码
// ParkingSystem.cpp - 主程序
#include <iostream>
#include <string>
#include <limits>

class ParkingSystem {
private:
    VehicleManager vehicleMgr;
    
    void clearInputBuffer() {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    
public:
    void run() {
        int choice;
        
        do {
            showMainMenu();
            std::cout << "请选择操作: ";
            std::cin >> choice;
            clearInputBuffer();
            
            switch (choice) {
                case 1:
                    processVehicleEntry();
                    break;
                case 2:
                    processVehicleExit();
                    break;
                case 3:
                    vehicleMgr.showParkingVehicles();
                    break;
                case 4:
                    showStatistics();
                    break;
                case 0:
                    std::cout << "感谢使用,再见!" << std::endl;
                    break;
                default:
                    std::cout << "无效选择,请重新输入!" << std::endl;
            }
            
            if (choice != 0) {
                std::cout << "\n按Enter键继续...";
                std::cin.get();
            }
            
        } while (choice != 0);
    }
    
private:
    void showMainMenu() {
        system("cls");  // Windows清屏,Linux用"clear"
        std::cout << "==================================" << std::endl;
        std::cout << "      停车场管理系统 v1.0" << std::endl;
        std::cout << "==================================" << std::endl;
        std::cout << "1. 车辆入场登记" << std::endl;
        std::cout << "2. 车辆出场结算" << std::endl;
        std::cout << "3. 查看停放车辆" << std::endl;
        std::cout << "4. 查看统计信息" << std::endl;
        std::cout << "0. 退出系统" << std::endl;
        std::cout << "==================================" << std::endl;
    }
    
    void processVehicleEntry() {
        std::string plate;
        int space;
        
        std::cout << "\n=== 车辆入场登记 ===" << std::endl;
        std::cout << "请输入车牌号: ";
        std::getline(std::cin, plate);
        
        std::cout << "请输入停车位号: ";
        std::cin >> space;
        clearInputBuffer();
        
        vehicleMgr.vehicleEntry(plate, space);
    }
    
    void processVehicleExit() {
        std::string plate;
        
        std::cout << "\n=== 车辆出场结算 ===" << std::endl;
        std::cout << "请输入车牌号: ";
        std::getline(std::cin, plate);
        
        vehicleMgr.vehicleExit(plate);
    }
    
    void showStatistics() {
        DatabaseHandler& db = DatabaseHandler::getInstance();
        
        // 统计总车辆数
        std::string totalSql = "SELECT COUNT(*) FROM vehicles";
        MYSQL_RES* result = db.query(totalSql);
        if (result) {
            MYSQL_ROW row = mysql_fetch_row(result);
            std::cout << "\n总停车记录: " << (row[0] ? row[0] : "0") << "条" << std::endl;
            mysql_free_result(result);
        }
        
        // 统计当前停放车辆
        std::string parkingSql = "SELECT COUNT(*) FROM vehicles WHERE status = 'parking'";
        result = db.query(parkingSql);
        if (result) {
            MYSQL_ROW row = mysql_fetch_row(result);
            std::cout << "当前停放车辆: " << (row[0] ? row[0] : "0") << "辆" << std::endl;
            mysql_free_result(result);
        }
        
        // 统计总收入
        std::string revenueSql = "SELECT SUM(amount) FROM payment_records";
        result = db.query(revenueSql);
        if (result) {
            MYSQL_ROW row = mysql_fetch_row(result);
            std::cout << "总收入: " << (row[0] ? row[0] : "0") << "元" << std::endl;
            mysql_free_result(result);
        }
    }
};

4.4 完整主程序

cpp 复制代码
// main.cpp - 程序入口
#include "DatabaseHandler.h"
#include "ParkingSystem.cpp"

int main() {
    // 设置控制台编码(Windows)
#ifdef _WIN32
    system("chcp 65001 > nul");
    system("title 停车场管理系统");
#endif
    
    std::cout << "==================================" << std::endl;
    std::cout << "  停车场管理系统启动中..." << std::endl;
    std::cout << "==================================" << std::endl;
    
    try {
        // 初始化数据库连接
        DatabaseHandler& db = DatabaseHandler::getInstance();
        if (!db.connect()) {
            std::cout << "数据库连接失败,程序退出!" << std::endl;
            return 1;
        }
        
        // 运行主系统
        ParkingSystem system;
        system.run();
        
    } catch (const std::exception& e) {
        std::cerr << "系统错误: " << e.what() << std::endl;
        std::cout << "按Enter键退出...";
        std::cin.get();
        return 1;
    }
    
    return 0;
}

五、常见问题与解决方案

5.1 编译错误解决

问题1:找不到mysql.h

错误:fatal error: mysql.h: No such file or directory

解决方案:

  1. 检查VS2019包含目录设置是否正确

  2. 确保MySQL Connector已正确安装

  3. 在项目属性中添加包含路径

问题2:链接错误

错误:LNK2019: 无法解析的外部符号

解决方案:

  1. 检查库目录设置

  2. 确认附加依赖项包含mysqlcppconn.lib

  3. 确保平台匹配(x64/x86)

5.2 运行时错误解决

问题1:连接数据库失败

解决方案:

  1. 检查MySQL服务是否启动

  2. 验证用户名和密码是否正确

  3. 检查防火墙设置

问题2:中文乱码

解决方案:

cpp 复制代码
// 在连接后设置字符集
mysql_set_character_set(connection, "utf8mb4");

六、项目扩展建议

6.1 功能扩展方向

1. 月卡会员系统
cpp 复制代码
class MonthlyMember {
private:
    struct MemberInfo {
        std::string member_id;
        std::string plate_number;
        std::string start_date;
        std::string end_date;
        double fee;
    };
    
public:
    bool addMember(const MemberInfo& member) {
        // 实现月卡会员添加逻辑
    }
    
    bool isMember(const std::string& plate) {
        // 检查是否为月卡会员
    }
};
2. 图形界面开发

使用Qt或MFC开发图形界面,提升用户体验:

cpp 复制代码
// Qt示例
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow() {
        QPushButton* entryBtn = new QPushButton("车辆入场", this);
        connect(entryBtn, &QPushButton::clicked, 
                this, &MainWindow::onEntryClicked);
    }
    
private slots:
    void onEntryClicked() {
        // 处理入场逻辑
    }
};

6.2 代码优化建议

1. 使用智能指针
cpp 复制代码
#include <memory>

class DatabaseManager {
private:
    std::unique_ptr<MYSQL, decltype(&mysql_close)> connection;
    
public:
    DatabaseManager() : connection(nullptr, &mysql_close) {
        connection.reset(mysql_init(nullptr));
    }
    
    // 自动管理资源,无需手动关闭
};
2. 添加日志系统
cpp 复制代码
class Logger {
public:
    enum LogLevel { INFO, WARNING, ERROR };
    
    static void log(LogLevel level, const std::string& message) {
        std::ofstream file("parking.log", std::ios::app);
        file << getCurrentTime() << " [" << toString(level) 
             << "] " << message << std::endl;
    }
};

七、学习路线建议

7.1 初学者学习路径

  1. 第一阶段:运行现有代码,理解基本流程

  2. 第二阶段:修改计费规则,添加新功能

  3. 第三阶段:优化代码结构,实现设计模式

  4. 第四阶段:开发图形界面,部署到服务器

7.2 推荐的进阶学习

  • C++进阶:《Effective C++》、《C++ Primer》

  • 数据库优化:《高性能MySQL》

  • 软件设计:《设计模式:可复用面向对象软件的基础》

  • 项目实战:参与开源项目,积累经验

八、总结

通过这个停车场管理系统的开发,你将掌握:

现代C++编程技巧

MySQL数据库设计与操作

软件架构设计思想

实际项目开发流程

问题调试与解决能力

这个项目不仅是一个学习工具,更是一个可以展示你编程能力的作品集项目

建议你在理解基础代码后,尝试添加自己的创新功能,比如:

  • 添加预约停车功能

  • 实现车牌识别接口

  • 开发手机端管理应用

  • 添加数据分析模块

记住:编程能力不是看会的,而是练会的。

动手实现这个项目,遇到问题解决问题,你的编程水平一定会有质的飞跃!

资源推荐:

C/C++学习交流君羊

C/C++教程

C/C++学习路线,就业咨询,技术提升

相关推荐
2501_930707782 小时前
如何使用C#代码将 Excel 文件转换为 SVG
开发语言·c#·excel
程序员修心2 小时前
CSS 盒子模型与布局核心知识点总结
开发语言·前端·javascript
亚历山大海2 小时前
PHP发送outlook(微软)OAuth 2.0企业版邮箱验证码
开发语言·php·outlook
.简.简.单.单.2 小时前
Design Patterns In Modern C++ 中文版翻译 第九章 装饰器
开发语言·c++·设计模式
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——两数相加
c++·算法·结构与算法
大叔_爱编程2 小时前
基于人脸识别的互联网课堂考勤系统-springboot
java·spring boot·毕业设计·人脸识别·源码·课程设计·课堂考勤系统
Hard but lovely2 小时前
Linux: posix标准:线程互斥&& 互斥量的原理&&抢票问题
linux·开发语言
XFF不秃头2 小时前
力扣刷题笔记-和为 K 的子数组
c++·笔记·算法·leetcode
w-w0w-w2 小时前
【无标题】
c++