核心内容摘要
StructBERT模型版本管理与回滚操作指南
C 中不同类之间尤其是这些类分散在不同头文件 / 源文件中时如何实现通信包括调用其他类的方法、访问其成员资源这是 C 面向对象编程中最基础且高频的核心需求之一。
C 跨类 / 跨源文件通信的核心是正确的头文件管理访问权限控制对象 / 引用 / 指针的持有下面我会从「基础常用方式」到「进阶解耦方式」逐步讲解每个方式都配可直接运行的多文件示例。
基础前提C 多文件编程规范跨源文件通信首先要遵守 C 的编译规则否则会出现「未定义引用」「重复定义」等错误头文件.h/.hpp只放类的声明、函数原型、宏定义不要放函数实现 / 变量定义静态成员除外源文件.cpp放类的方法实现、函数体头文件保护用#pragma once或#ifndef避免重复包含编译链接编译时需将所有相关.cpp 文件一起编译如g A.cpp B.cpp main.cpp -o app。
核心通信方式从简单到进阶方式 1直接包含头文件 持有对象 / 指针 / 引用最常用这是最基础、最通用的方式一个类通过包含另一个类的头文件创建其对象或持有指针 / 引用从而调用其公开方法 / 成员。
示例场景User.h/User.cpp定义用户类包含「获取用户名」的方法Order.h/Order.cpp定义订单类需要调用 User 类的方法生成订单main.cpp测试入口。
User.h头文件类声明// 头文件保护避免重复包含 #pragma once #include string // 类声明public修饰其他源文件可访问 class User { private: std::string username; // 私有成员需通过public方法访问 public: // 构造函数声明 User(const std::string name); // 公开方法获取用户名 std::string getUsername() const; // 公开方法设置用户名 void setUsername(const std::string name); };
User.cpp源文件方法实现#include User.h // 包含自身头文件 // 构造函数实现 User::User(const std::string name) : username(name) {} // 获取用户名实现 std::string User::getUsername() const { return username; } // 设置用户名实现 void User::setUsername(const std::string name) { username name; }
Order.h头文件依赖 User 类#pragma once #include string #include User.h // 包含User类的头文件才能使用User类 class Order { private: std::string orderId; User* user; // 持有User类的指针推荐指针/引用避免拷贝 public: // 构造函数传入User对象的指针 Order(const std::string id, User* u); // 生成订单描述调用User的方法 std::string generateOrderDesc() const; };
Order.cpp源文件方法实现#include Order.h // 构造函数实现 Order::Order(const std::string id, User* u) : orderId(id), user(u) {} // 核心调用User类的public方法 std::string Order::generateOrderDesc() const { if (user nullptr) { return 订单[ orderId ]无关联用户; } return 订单[ orderId ]用户 user-getUsername() 的订单; }
main.cpp测试入口#include iostream #include User.h #include Order.h int main() { // 创建User对象 User user(张
; // 创建Order对象传入User的指针 Order order(OD123456, user); // 调用Order的方法内部会调用User的方法 std::cout order.generateOrderDesc() std::endl; // 直接修改User对象Order会感知到因为持有指针 user.setUsername(李
; std::cout order.generateOrderDesc() std::endl; return 0; }编译运行命令Linux/macOSg User.cpp Order.cpp main.cpp -o cross_class_demo ./cross_class_demo输出结果订单[OD123456]用户张三的订单 订单[OD123456]用户李四的订单方式 2静态成员 / 方法无需创建对象如果某个类的方法 / 成员是「共享资源」比如全局配置、工具方法可以定义为static无需创建对象就能直接调用跨类 / 跨文件使用更便捷。
示例工具类 Tool跨文件调用静态方法Tool.h#pragma once #include string class Tool { public: // 静态方法字符串拼接工具方法 static std::string concat(const std::string a, const std::string b); // 静态成员全局共享的版本号 static const std::string VERSION; };Tool.cpp#include Tool.h // 静态方法实现 std::string Tool::concat(const std::string a, const std::string b) { return a - b; } // 静态成员初始化必须在源文件中不能在头文件 const std::string Tool::VERSION
1.
0;其他类调用比如 Order.cpp 中#include Order.h #include Tool.h // 包含Tool头文件 std::string Order::generateOrderDesc() const { if (user nullptr) { return 订单[ orderId ]无关联用户; } // 调用静态方法无需创建Tool对象直接类名::方法名 std::string fullName Tool::concat(user-getUsername(), 用户); // 访问静态成员 return V Tool::VERSION 订单[ orderId ] fullName; }方式 3友元谨慎使用破坏封装友元friend允许一个类 / 函数访问另一个类的私有 / 保护成员但会破坏封装性仅在特殊场景如紧密耦合的工具类使用。
示例让 Order 成为 User 的友元修改User.h#pragma once #include string // 前向声明告诉编译器Order类存在避免循环包含 class Order; class User { private: std::string username; // 声明Order是友元类Order可访问User的私有成员 friend class Order; public: User(const std::string name) : username(name) {} };此时Order.cpp中可直接访问 User 的私有成员username无需通过getUsername()std::string Order::generateOrderDesc() const { if (user nullptr) { return 订单[ orderId ]无关联用户; } // 直接访问私有成员因为是友元 return 订单[ orderId ]用户 user-username; }方式 4前向声明解决「循环包含」问题如果类 A 包含类 B 的头文件类 B 又包含类 A 的头文件会导致「循环包含」编译错误此时用前向声明forward declaration解决。
示例A 和 B 互相依赖// A.h #pragma once // 前向声明B类仅告诉编译器B是一个类不包含具体定义 class B; class A { private: B* b_ptr; // 只能用指针/引用不能定义B的对象因为未看到B的完整定义 public: void setB(B* b); void callBMethod(); }; // B.h #pragma once // 前向声明A类 class A; class B { private: A* a_ptr; public: void setA(A* a); void callAMethod(); // 公开方法供A调用 void doSomething() const; };然后在.cpp文件中包含完整头文件// A.cpp #include A.h #include B.h // 包含完整B的定义 void A::setB(B* b) { b_ptr b; } void A::callBMethod() { if (b_ptr) { b_ptr-doSomething(); // 可调用B的方法 } }方式 5抽象类 / 接口进阶解耦通过纯虚函数定义「接口」子类实现具体逻辑跨类通信时依赖接口而非具体类大幅降低耦合符合「依赖倒置原则」。
示例定义 Pay 接口WeChatPay/Alipay 实现Order 调用接口// PayInterface.h接口类纯虚函数 #pragma once #include string class PayInterface { public: // 纯虚函数支付接口 virtual bool pay(double amount) 0; // 虚析构函数避免内存泄漏 virtual ~PayInterface() default; }; // WeChatPay.h #pragma once #include PayInterface.h class WeChatPay : public PayInterface { public: bool pay(double amount) override { std::cout 微信支付 amount 元 std::endl; return true; } }; // Order.h依赖接口不依赖具体支付方式 #pragma once #include PayInterface.h // 包含接口头文件 class Order { private: PayInterface* pay_ptr; // 持有接口指针 double amount; public: Order(PayInterface* pay, double amt) : pay_ptr(pay), amount(amt) {} void doPay() { if (pay_ptr) { pay_ptr-pay(amount); } } };调用时可灵活替换支付方式无需修改 Order 类// main.cpp #include WeChatPay.h #include Order.h int main() { WeChatPay wechat; Order order(wechat,
99.
; order.doPay(); // 输出微信支付
9