C++中实现向量数据多表示形式修改的方案咨询
PointContainer 设计实现方案
核心思路
底层仅存储笛卡尔坐标点(CartPoint),通过迭代器适配器实现两种坐标体系的访问与修改:
- 访问笛卡尔坐标时直接返回底层数据;
- 访问极坐标时实时转换笛卡尔坐标为极坐标;
- 修改极坐标时,将新的极坐标转换回笛卡尔坐标更新底层存储。
这种方案避免了双存储的内存浪费,同时保证数据一致性。
基础定义与转换函数
补全基础结构和转换逻辑:
#include <vector> #include <cmath> #include <type_traits> // 笛卡尔坐标点 struct CartPoint { double x; double y; }; // 极坐标点(alpha为弧度制) struct PolarPoint { double r; double alpha; }; // 笛卡尔转极坐标 void translate(const CartPoint& from, PolarPoint& to) { to.r = std::sqrt(from.x * from.x + from.y * from.y); to.alpha = std::atan2(from.y, from.x); } // 极坐标转笛卡尔 void translate(const PolarPoint& from, CartPoint& to) { to.x = from.r * std::cos(from.alpha); to.y = from.r * std::sin(from.alpha); }
迭代器适配器实现
实现模板迭代器适配器,包装底层std::vector<CartPoint>::iterator,根据目标类型处理访问和赋值:
// 迭代器适配器:适配底层CartPoint迭代器,支持目标类型的访问与修改 template <typename TargetPoint> class PointIteratorAdapter { public: using iterator_category = std::random_access_iterator_tag; using value_type = TargetPoint; using difference_type = std::ptrdiff_t; using pointer = TargetPoint*; using reference = TargetPoint&; explicit PointIteratorAdapter(std::vector<CartPoint>::iterator it) : m_it(it) {} // 解引用:返回目标类型的临时对象(按需转换) TargetPoint operator*() const { if constexpr (std::is_same_v<TargetPoint, CartPoint>) { return *m_it; } else { PolarPoint res; translate(*m_it, res); return res; } } // 赋值:将目标类型转换为CartPoint更新底层 PointIteratorAdapter& operator=(const TargetPoint& val) { if constexpr (std::is_same_v<TargetPoint, CartPoint>) { *m_it = val; } else { CartPoint cart_val; translate(val, cart_val); *m_it = cart_val; } return *this; } // 基础迭代器操作 PointIteratorAdapter& operator++() { ++m_it; return *this; } PointIteratorAdapter operator++(int) { auto temp = *this; ++m_it; return temp; } PointIteratorAdapter& operator--() { --m_it; return *this; } PointIteratorAdapter operator--(int) { auto temp = *this; --m_it; return temp; } // 随机访问操作 PointIteratorAdapter operator+(difference_type n) const { return PointIteratorAdapter(m_it + n); } PointIteratorAdapter operator-(difference_type n) const { return PointIteratorAdapter(m_it - n); } difference_type operator-(const PointIteratorAdapter& other) const { return m_it - other.m_it; } // 比较操作 bool operator==(const PointIteratorAdapter& other) const { return m_it == other.m_it; } bool operator!=(const PointIteratorAdapter& other) const { return m_it != other.m_it; } private: std::vector<CartPoint>::iterator m_it; }; // 迭代器范围包装类,支持范围for循环 template <typename TargetPoint> class IteratorRange { public: IteratorRange(std::vector<CartPoint>::iterator begin, std::vector<CartPoint>::iterator end) : m_begin(begin), m_end(end) {} PointIteratorAdapter<TargetPoint> begin() const { return PointIteratorAdapter<TargetPoint>(m_begin); } PointIteratorAdapter<TargetPoint> end() const { return PointIteratorAdapter<TargetPoint>(m_end); } private: std::vector<CartPoint>::iterator m_begin; std::vector<CartPoint>::iterator m_end; };
PointContainer 类实现
封装底层存储,对外提供迭代器访问和批量导出接口:
class PointContainer { public: // 构造函数:接收CartPoint向量(优先移动语义减少拷贝) explicit PointContainer(std::vector<CartPoint> pts) : m_points(std::move(pts)) {} // 获取对应类型的迭代器范围,支持范围for template <typename TargetPoint> IteratorRange<TargetPoint> GetIterator() { static_assert(std::is_same_v<TargetPoint, CartPoint> || std::is_same_v<TargetPoint, PolarPoint>, "TargetPoint must be CartPoint or PolarPoint"); return IteratorRange<TargetPoint>(m_points.begin(), m_points.end()); } // 导出对应类型的完整向量 template <typename TargetPoint> std::vector<TargetPoint> Retrive() const { static_assert(std::is_same_v<TargetPoint, CartPoint> || std::is_same_v<TargetPoint, PolarPoint>, "TargetPoint must be CartPoint or PolarPoint"); std::vector<TargetPoint> res; res.reserve(m_points.size()); if constexpr (std::is_same_v<TargetPoint, CartPoint>) { res = m_points; } else { for (const auto& cart_pt : m_points) { PolarPoint polar_pt; translate(cart_pt, polar_pt); res.push_back(polar_pt); } } return res; } private: std::vector<CartPoint> m_points; // 底层唯一存储:笛卡尔坐标 };
使用示例
完全符合期望的调用方式:
void fillVectorWithCartPts(std::vector<CartPoint>& points) { points.emplace_back(1.0, 0.0); points.emplace_back(0.0, 1.0); points.emplace_back(1.0, 1.0); } int main() { std::vector<CartPoint> pts{}; fillVectorWithCartPts(pts); PointContainer pc{std::move(pts)}; // 通过笛卡尔迭代器修改点 for (auto& pt : pc.GetIterator<CartPoint>()) { pt.x += 1.0; pt.y += 1.0; } // 通过极坐标迭代器修改点 for (auto& pt : pc.GetIterator<PolarPoint>()) { pt = PolarPoint{3.0, M_PI_4}; // 直接赋值极坐标点 } // 导出两种坐标的向量 std::vector<PolarPoint> polarRes = pc.Retrive<PolarPoint>(); std::vector<CartPoint> cartRes = pc.Retrive<CartPoint>(); return 0; }
替代方案
1. 双存储同步方案
同时存储std::vector<CartPoint>和std::vector<PolarPoint>,修改其中一种时同步更新另一种。优点是访问速度快,无需实时转换;缺点是内存占用翻倍,且需要维护一致性,适合频繁同时访问两种坐标的场景。
2. 代理对象方案
返回持有CartPoint引用的代理类,通过代理类的属性访问/修改极坐标:
class PolarProxy { public: explicit PolarProxy(CartPoint& cart_pt) : m_cart_pt(cart_pt) {} // 获取极坐标属性 double r() const { return std::sqrt(m_cart_pt.x*m_cart_pt.x + m_cart_pt.y*m_cart_pt.y); } double alpha() const { return std::atan2(m_cart_pt.y, m_cart_pt.x); } // 修改极坐标属性 void set_r(double new_r) { double alpha = std::atan2(m_cart_pt.y, m_cart_pt.x); m_cart_pt.x = new_r * std::cos(alpha); m_cart_pt.y = new_r * std::sin(alpha); } void set_alpha(double new_alpha) { double r = std::sqrt(m_cart_pt.x*m_cart_pt.x + m_cart_pt.y*m_cart_pt.y); m_cart_pt.x = r * std::cos(new_alpha); m_cart_pt.y = r * std::sin(new_alpha); } private: CartPoint& m_cart_pt; };
这种方案支持细粒度修改极坐标的单个属性(如只修改r或只修改alpha),比直接赋值整个PolarPoint更灵活。
内容的提问来源于stack exchange,提问作者Piotr Cukier
相关产品推荐
相关产品推荐

