C ++类中的计算成员,由带有隐式转换超载的空结构成员组成

维克多·康迪诺

在某些数据结构中,拥有成员的值是在访问时从其他数据成员计算而来的,而不是存储这些成员将是有用的。

例如,对于需要相对尺寸而不是绝对尺寸的客户端,典型的rect类可能会将其lefttoprightbottom坐标存储在成员数据字段中,并提供getter方法根据这些值返回计算出的宽度高度。职位。

struct rect
{
   int left, top, right, bottom;

   // ...

   int get_width() const { return right - left; }
   int get_height() const { return bottom - top; }
};

此实现使我们能够获取并设置矩形边的绝对坐标,

float center_y = (float)(box.top + box.bottom) / 2.0;

并获得相对尺寸,尽管使用的方法调用操作符表达式语法略有不同

float aspect = (float)box.get_width() / (float)box.get_height();

问题

但是,人们可能会争辩说,存储相对宽度高度而不是绝对的坐标坐标是同等有效的,并且要求需要计算值的客户端才能使用getter方法。

我的解决方案

为了避免记住哪种情况需要方法调用与数据成员访问运算符语法,我想出了一些可在当前稳定的gcc和clang编译器中运行的代码。这是rect数据结构的完整功能示例实现

#include <iostream>

struct rect
{
  union {
    struct {
      union { int l; int left; };
      union { int t; int top; };
      union { int r; int right; };
      union { int b; int bot; int bottom; };
    };
    struct {
      operator int() {
        return ((rect*)this)->r - ((rect*)this)->l;
      }
    } w, width;
    struct {
      operator int() {
        return ((rect*)this)->b - ((rect*)this)->t;
      }
    } h, height;
  };

  rect(): l(0), t(0), r(0), b(0) {}
  rect(int _w, int _h): l(0), t(0), r(_w), b(_h) {}
  rect(int _l, int _t, int _r, int _b): l(_l), t(_t), r(_r), b(_b) {}

  template<class OStream> friend OStream& operator<<(OStream& out, const rect& ref)
  {
    return out << "rect(left=" << ref.l << ", top=" << ref.t << ", right=" << ref.r << ", bottom=" << ref.b << ")";
  }
};

/// @brief Small test program showing that rect.w and rect.h behave like data members

int main()
{
  rect t(3, 5, 103, 30);
  std::cout << "sizeof(rect) is " << sizeof(rect) << std::endl;
  std::cout << "t is " << t << std::endl;
  std::cout << "t.w is " << t.w << std::endl;
  std::cout << "t.h is " << t.h << std::endl;

  return 0;
}

我在这里做什么有什么问题吗?

关于嵌套的空结构类型的隐式转换运算符中的指针转换的一些说明,即这些行:

return ((rect*)this)->r - ((rect*)this)->l;

感觉很脏,好像我可能违反了良好的C ++样式约定。如果解决方案的这一方面或其他方面是错误的,我想知道原因是什么,最终,如果这是不好的做法,那么有一种有效的方法可以达到相同的结果

朗布拉克

我通常希望工作的一件事不会:

auto w = t.w;

此外,以下行之一有效,而另一行无效:

t.l += 3;
t.w += 3; // compile error

因此,您没有改变用户需要知道哪些成员是数据和哪些是函数的事实。

我只是让它们全部起作用。无论如何,这是更好的封装。我希望使用全名,即左,上,下,右,宽度和长度。编写的字符可能更多,但是大多数代码的读取次数要比其编写的次数多。多余的几个字符将得到回报。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章