C ++索引类成员

时间:2014-10-31 08:35:08

标签: c++

我有一个类向量

class vector3f
{
public:
float x;
float y;
float z;
};

如果我想访问其中一个成员,我必须输入vec.x,vec.y和vec.z. 现在,我有一个应该按索引访问数据成员的算法,例如:

for(int i = 0; i < 3; i++)
{
vec[i] = i*i;
}

在没有索引的情况下执行此操作将导致多个if条件:

for(int i = 0; i < 3; i++)
{
if(i == 0){vec.x = i*i;}
else if(i == 1){vec.y = i*i;}
else if(i == 2){vec.z = i*i;}
}

有没有办法索引数据成员,以便在编译时解析它们? 我不想在向量类中使用数组,因为使用vec.x,vec.y和vec.z访问数据成员对程序员来说更方便。什么是避免这些if条件的最佳解决方案?

3 个答案:

答案 0 :(得分:5)

您可以为您的班级重载operator[],将这些if条件(或最好是switch)本地化为一个地方:

class vector3f
{
public:
  float x;
  float y;
  float z;

  float& operator[] (size_t i)
  {
    switch (i) {
      case 0: return x;
      case 1: return y;
      case 2: return z;
      default: throw "something";
    }
  }

  float operator[] (size_t i) const
  { return (*const_cast<vector3f*>(this))[i];
}

这是实现这一目标的通用和安全的方式。

如果你的类实际上是标准布局类 1 ,正如你所示, if 你知道对齐和填充方案您的编译器/平台,如果你知道这些float只会在内存中相继排列,你也可以像这样实现运算符:

float& operator[] (size_t i)
{
  return (&x)[i];
}

这会将x视为float数组的开头。它会更快,但依赖于我上面提到的 ifs ,并且不会进行边界检查。


1 这基本上意味着它没有非空基类,没有virtual函数,也没有数据成员非标准布局类型。

答案 1 :(得分:1)

在编译时并非绝对,但您可以进行优化。

您可以使用指针到成员变量,然后使用其数组。从:

开始
float vector3f::*px;
px = &vector3f::x;
(vec.*px) = 10.2;

然后声明指向成员的数组:

float vector3f::*pArray[3];

分配它们:

pArray[0] = &vector3f::x;
pArray[1] = &vector3f::y;
pArray[2] = &vector3f::z;

使用它们:

(vec.*pArray[0]) = 10.2; // This is vector3f::x
(vec.*pArray[1]) = 1042.5; // This is vector3f::y

并适当地更改循环体以索引适当的指向成员的指针!

答案 2 :(得分:0)

使用references可以获得一个有趣的替代方案。

class vector3f
{
public:
  float &x, &y, &z;
  float value[3];

  vector3f() :
    x(value[0]), y(value[1]), z(value[2]){}
};

这里我们将x绑定到值[0],y绑定到值[1],z绑定到值[2] - 它们是别名,用于数组中的条目,但请注意它们确实分配了在类中每个引用额外4个字节。这样,我们可以命名我们的数组以方便用户访问。

我们也可以避免对重载operator [的运行时调用(但是好的编译器应该在交换机/案例中内联访问)。

使用示例:

vector3f test;
test.value[0] = 227.f;
test.value[1] = 42.f;
test.value[2] = -1.f;
printf("Values are %lf, %lf and %lf.",test.x,test.y,test.z);

结果输出:

Values are 227.000000, 42.000000 and -1.000000.