这个C++语法是什么意思,为什么它能够工作?

15
我在查看OpenDE的源代码时发现了一些奇怪的用法,使用类的数组索引运算符'[]'。以下是一个简化的例子展示此语法:
#include <iostream>

class Point
{
public:
    Point() : x(2.8), y(4.2), z(9.5) {}

    operator const float *() const
    {
        return &x;
    }

private:
    float x, y, z;
};

int main()
{
    Point p;
    std::cout << "x: " << p[0] << '\n'
              << "y: " << p[1] << '\n'
              << "z: " << p[2];
}

输出:

x: 2.8
y: 4.2
z: 9.5

这里发生了什么?为什么这个语法可以工作?Point类没有重载operator [],但是这里的代码正在尝试进行某种自动转换到float。

我以前从未见过这种用法--至少看起来很不寻常和令人惊讶。

谢谢


4
请注意,要确定代码是使用operator[]还是指针转换函数,可以通过以下奇怪的测试:如果0[p]能够正常工作,则表示使用了指针转换。如果0[p]无法正常工作,但p[0]可以正常工作,则表示使用了operator[] - Johannes Schaub - litb
3个回答

17

p被隐式转换为指向xconst float* const,因此*px*(p+1)y,以此类推。

当然,这种做法非常奇怪(而且令人困惑!)。如果他们确实想要这样做,通常最好将x、y和z存储在数组中,并编写一个函数来获取整个数组。


19
更不用说这完全是不安全的,因为 xyz 在内存中的位置没有被明确定义。 - D.Shawley
2
@D.Shawley:说得好。虽然“合理”的编译器可能会这样做,但我不认为有任何保证这种布局是标准的。 - rlbond
3
另一个缺点是,如果你意外将 Point 对象用作布尔值,它会神秘地“起作用”,并且始终返回 true,因为它强制转换 Point -> 指针 -> 布尔值。 - Henk
2
@Jonathan Leffler,您是正确的,这是由C++标准9.2/12保证的:“未经访问说明符介入声明的(非联合)类的非静态数据成员被分配,以便稍后的成员在类对象内具有更高的地址。” - Kirill V. Lyadvinsky
3
@Jonathan Leffler:顺序有保证,但不能保证 y 立即跟在 x 后面。编译器可能会为任何原因插入填充。 - D.Shawley
显示剩余6条评论

8

这里的想法是通过下标或名称为 Point 的成员提供访问权限。如果您想这样做,最好重载 operator[],类似于以下内容:

struct Point { 
    float x, y, z;

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

这样做的好处是,如果编译器在浮点数之间插入填充(padding),它仍然可以正常工作 -- 任何能够读懂C++的人都应该能够轻松理解,不会有任何问题。


1
好观点。这也是我所思考的。我知道当我浏览源代码时,代码在做什么并不明显。我认为这绝对属于“过于聪明而不好的代码”。 :P - greatwolf
+1 对于“正确”的代码 - 安全,处理错误,易读等。 - JBRWilkinson

1

这只是将成员数据视为数组的一种方法。您也可以使用结构体来实现这一点。当您想要可读性,但又想能够迭代简单数据结构时,这非常有用。一个示例用途是以这种方式声明矩阵:

typedef struct {
   CGFloat m11,m12,m13,m14;
   CGFloat m21,m22,m23,m24;
   CGFloat m31,m32,m33,m34;
   CGFloat m41,m42,m43,m44;
} CATransform3D;

您可以通过名称方便地引用每个单元格,但是您也可以在任何地方传递指向m11的指针(并且C将把您的结构视为数组,其中m11是第一个元素),并迭代所有元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接