错误16error C2011: “Bullet”:“class”类型重定义,如何解决

本文探讨了C++中类相互调用时头文件的正确包含方式,避免编译错误。通过调整头文件的包含位置,即从.h文件移至.cpp文件,可以有效解决循环依赖问题。

小菜学习心得 发现在c++类的相互调用中我们的头文件所加的位置跟相互调用是有关系的,如以下一个例子:

在TowerDefend头文件中导入了这些头文件


在Bullet想要调用到TowerDefend时,在cpp文件中导入了TowerDefend.h

当此时就会出现一个意想不到的错误了


我试了多次 发现得这样改,把添加到TowerDefend的要导入的头文件不要在.h文件中导入,就不会出现以上错误了

在TowerDefend.cpp

在Bullet.ccp文件中

这样调用类就不会出错了,所以建议把导入的头文件,非一定要在.h文件的,都弄到ccp文件中比较合适,方便调用。

#include "cboard.hpp" #include "tools/math_tools.hpp" #include "tools/yaml.hpp" namespace io { CBoard::CBoard(const std::string & config_path) : mode(Mode::idle), shoot_mode(ShootMode::left_shoot), bullet_speed(0), queue_(5000), can_(read_yaml(config_path), std::bind(&CBoard::callback, this, std::placeholders::_1)) // 注意: callback的运行会早于Cboard构造函数的完成 { tools::logger()->info("[Cboard] Waiting for q..."); queue_.pop(data_ahead_); queue_.pop(data_behind_); tools::logger()->info("[Cboard] Opened."); } Eigen::Quaterniond CBoard::imu_at(std::chrono::steady_clock::time_point timestamp) { if (data_behind_.timestamp < timestamp) data_ahead_ = data_behind_; while (true) { queue_.pop(data_behind_); if (data_behind_.timestamp > timestamp) break; data_ahead_ = data_behind_; } Eigen::Quaterniond q_a = data_ahead_.q.normalized(); Eigen::Quaterniond q_b = data_behind_.q.normalized(); auto t_a = data_ahead_.timestamp; auto t_b = data_behind_.timestamp; auto t_c = timestamp; std::chrono::duration<double> t_ab = t_b - t_a; std::chrono::duration<double> t_ac = t_c - t_a; // 四元数插值 auto k = t_ac / t_ab; Eigen::Quaterniond q_c = q_a.slerp(k, q_b).normalized(); return q_c; } void CBoard::send(Command command) const { can_frame frame; frame.can_id = send_canid_; frame.can_dlc = 8; frame.data[0] = (command.control) ? 1 : 0; frame.data[1] = (command.shoot) ? 1 : 0; frame.data[2] = (int16_t)(command.yaw * 1e4) >> 8; frame.data[3] = (int16_t)(command.yaw * 1e4); frame.data[4] = (int16_t)(command.pitch * 1e4) >> 8; frame.data[5] = (int16_t)(command.pitch * 1e4); frame.data[6] = (int16_t)(command.horizon_distance * 1e4) >> 8; frame.data[7] = (int16_t)(command.horizon_distance * 1e4); try { can_.write(&frame); } catch (const std::exception & e) { tools::logger()->warn("{}", e.what()); } } void CBoard::callback(const can_frame & frame) { auto timestamp = std::chrono::steady_clock::now(); if (frame.can_id == quaternion_canid_) { auto x = (int16_t)(frame.data[0] << 8 | frame.data[1]) / 1e4; auto y = (int16_t)(frame.data[2] << 8 | frame.data[3]) / 1e4; auto z = (int16_t)(frame.data[4] << 8 | frame.data[5]) / 1e4; auto w = (int16_t)(frame.data[6] << 8 | frame.data[7]) / 1e4; if (std::abs(x * x + y * y + z * z + w * w - 1) > 1e-2) { tools::logger()->warn("Invalid q: {} {} {} {}", w, x, y, z); return; } queue_.push({{w, x, y, z}, timestamp}); } else if (frame.can_id == bullet_speed_canid_) { bullet_speed = (int16_t)(frame.data[0] << 8 | frame.data[1]) / 1e2; mode = Mode(frame.data[2]); shoot_mode = ShootMode(frame.data[3]); ft_angle = (int16_t)(frame.data[4] << 8 | frame.data[5]) / 1e4; // 限制日志输出频率为1Hz static auto last_log_time = std::chrono::steady_clock::time_point::min(); auto now = std::chrono::steady_clock::now(); if (bullet_speed > 0 && tools::delta_time(now, last_log_time) >= 1.0) { tools::logger()->info( "[CBoard] Bullet speed: {:.2f} m/s, Mode: {}, Shoot mode: {}, FT angle: {:.2f} rad", bullet_speed, MODES[mode], SHOOT_MODES[shoot_mode], ft_angle); last_log_time = now; } } } // 实现方式有待改进 std::string CBoard::read_yaml(const std::string & config_path) { auto yaml = tools::load(config_path); quaternion_canid_ = tools::read<int>(yaml, "quaternion_canid"); bullet_speed_canid_ = tools::read<int>(yaml, "bullet_speed_canid"); send_canid_ = tools::read<int>(yaml, "send_canid"); if (!yaml["can_interface"]) { throw std::runtime_error("Missing 'can_interface' in YAML configuration."); } return yaml["can_interface"].as<std::string>(); } } // namespace io #ifndef IO__CBOARD_HPP #define IO__CBOARD_HPP #include <Eigen/Geometry> #include <chrono> #include <cmath> #include <functional> #include <string> #include <vector> #include "io/command.hpp" #include "io/socketcan.hpp" #include "tools/logger.hpp" #include "tools/thread_safe_queue.hpp" namespace io { enum Mode { idle, auto_aim, small_buff, big_buff, outpost }; const std::vector<std::string> MODES = {"idle", "auto_aim", "small_buff", "big_buff", "outpost"}; // 哨兵专有 enum ShootMode { left_shoot, right_shoot, both_shoot }; const std::vector<std::string> SHOOT_MODES = {"left_shoot", "right_shoot", "both_shoot"}; class CBoard { public: double bullet_speed; Mode mode; ShootMode shoot_mode; double ft_angle; //无人机专有 CBoard(const std::string & config_path); Eigen::Quaterniond imu_at(std::chrono::steady_clock::time_point timestamp); void send(Command command) const; private: struct IMUData { Eigen::Quaterniond q; std::chrono::steady_clock::time_point timestamp; }; tools::ThreadSafeQueue<IMUData> queue_; // 必须在can_之前初始化,否则存在死锁的可能 SocketCAN can_; IMUData data_ahead_; IMUData data_behind_; int quaternion_canid_, bullet_speed_canid_, send_canid_; void callback(const can_frame & frame); std::string read_yaml(const std::string & config_path); }; } // namespace io #endif // IO__CBOARD_HPP can通信改成串口通信
最新发布
12-01
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值