C++ C++;运算符[]重载SNAFU

C++ C++;运算符[]重载SNAFU,c++,operator-overloading,constants,C++,Operator Overloading,Constants,我想为一个类定义[]运算符。该类持有一个串行数据包(以及对该数据包进行操作的相关函数)。我想让用户有能力做这样的事情 MyClass packet; uint8_t byte = packet[3]; // get third byte of packet 我想阻止用户这样做 packet[3] = 0xAA; // this breaks encapsulation for my class :( 我一直在寻找解决方案,我想知道这个声明是否就是我所需要的(以及.cpp中的相关代码):

我想为一个类定义[]运算符。该类持有一个串行数据包(以及对该数据包进行操作的相关函数)。我想让用户有能力做这样的事情

MyClass packet;
uint8_t byte = packet[3];  // get third byte of packet
我想阻止用户这样做

packet[3] = 0xAA;  // this breaks encapsulation for my class :(
我一直在寻找解决方案,我想知道这个声明是否就是我所需要的(以及.cpp中的相关代码):

虽然我相当肯定这会奏效,但我对我的方法仍有一些不确定性,我希望你能帮助我解决我的问题

  • 只返回值而不是引用是否“确定”?我知道在我看到的所有示例中,都返回了一个引用。返回值是否有助于我避免在操作的左侧使用“[]”这个事实?再说一遍,const不阻止这一点吗

  • 即使在非常量对象上也会调用常量函数吗?我见过几个例子,其中有一个常量形式的运算符和一个非常量形式的运算符。非常量允许写入,而常量仅允许读取,但仅对常量对象调用。我的目标是让非常量对象也只能从中读取

  • 是否有一种干净的方法来传递操作员的错误?我的主要问题是,所请求的数据可能超出了我拥有的数据的范围。我所看到的所有示例都使用断言,但我不一定希望在用户对操作员的调用引起某种欢闹时程序崩溃。我也不一定要传回一个特殊的代码,因为我传回的字节的任何值都可能是有效的

  • 一如既往,感谢您的帮助,因为我慢慢地(但肯定地)从C程序员到OcC++向导的可怕转变。

  • 是的,对于像
    uint8\t
    这样的小类型,只返回一个值是可以的。您可以返回const引用,
    const
    确实会阻止任何人通过它进行写入。但是对于像
    uint8\t
    这样的小类型,按值返回是一个更好的主意。请注意,顺便说一句,当按值返回时,您不再需要返回类型上的
    const

    返回常量引用(即使很难防止修改)使调用代码能够创建和存储指向数组元素的潜在长期引用和指针,如中所示

    const uint8_t *byte = &packet[3];
    
    如果这是不需要的,那么按值返回也会阻塞该功能

  • 是的,将为非常量对象调用函数的
    const
    版本(假设您没有提供非常量版本)

  • 专门为此目的提出了例外情况。异常为错误情况提供了专用的反馈路径,而不会影响函数声明和规范(即,您不必为错误返回保留任何值,也不必为此引入任何参数)

  • 如果按值返回并使用

    编译器会给您一个错误,因为数据包[3]不是可修改的l值,这意味着它不能出现在赋值的左侧

    如果通过引用返回,则用户可以编辑引用的内容。您可以使用常量引用来禁止修改


    引用方法的优点是可以避免值的副本,如果运算符[]的返回值较大,则可以提高效率/空间。如果您只希望运算符[]的返回值存在一个副本,则必须使用(const)引用。

    您真的要求代码不能在字符大于8位的系统上编译吗?因为这就是
    uint8\u t
    所做的:它不存在,除非系统有一个正好有8位的无符号类型。当然
    uint\u-least8\u-t
    uint\u-fast8\u-t
    更合适。或者更好的是,
    unsigned char
    ,它将始终至少是8位。我使用uint_8t,因为根据谷歌的样式指南,这是首选方法。此外,packet类永远不会在一个我无法获得8位的无符号类型的系统上运行。谷歌的样式指南以经常被误导而闻名。它当然在这里,因为它不必要地使代码不可移植。
    const uint8_t *byte = &packet[3];
    
     packet[3] = 0xAA;