为什么会这样?

时间:2011-10-15 13:02:02

标签: c++ const

给出以下代码:

class TestA
{
    private:
        char Temp;

    public:
        char *Ptr;

        TestA(){Ptr = NULL; Temp = 'A'; Ptr = &Temp;}
        void Function(){Ptr = &Temp; Temp = 'B';}

        void operator=(const TestA &ItemCopy)
        {
            //ItemCopy.Temp = 'N'; //Not permitted
            printf("%c!\n",ItemCopy.Temp);
            Ptr = ItemCopy.Ptr; //This is okay
            *Ptr = 'M'; //This is okay, but it re-assigns ItemCopy.Temp. What?
            printf("%c!\n",ItemCopy.Temp);
        }
};

int main()
{
    TestA Temp1,Temp2;

    Temp1.Function();
    Temp2 = Temp1;
}

产生以下内容:

  


  M

即使ItemCopy是const。为什么我被允许间接修改它甚至取指针的非常量副本?

5 个答案:

答案 0 :(得分:9)

由于ItemCopy是常量,ItemCopy.Ptr具有有效类型char * const。指针是const,但可以修改指向的项目。这意味着作业:

*ItemCopy.Ptr = 'M';

是有意义且允许的(底层对象本身不是const),复制指针并通过它完成分配也是合法的。直接分配ItemCopy.Temp = 'M'不合法,但这并不意味着如果您拥有另一个非ItemCopy.Temp访问路径,则无法修改变量const

答案 1 :(得分:2)

指针别名。通过将ItemCopy::Ptr分配给this->Ptr,您可以为指针添加别名,并通过它指定另一个值。写这样的东西时还记得rule of 3

答案 2 :(得分:2)

Ptr指向ItemCopy.Ptr,后者又指向Temp。因此,当您取消引用它时,您将写入Temp

答案 3 :(得分:1)

语义:

    const TestA &ItemCopy

只能保证指针成员ItemCopy.Temp本身不能直接修改,指针指向的内容不能保证是const。

答案 4 :(得分:0)

这是因为const规则在编译时应用,但是这种规避是运行时状态的结果。制作const引用对象成员的非常量副本不会修改对象,因此不会违反const引用。这是因为只要编译器知道,你所做的就是制作一个值的副本,即一段记忆的地址。它不会预测您可能会在此处或其他地方取消引用它 - 它不会将constness应用于内存位置,而是应用于标识符,并且您尚未违反。

在运行时,为非const ptr分配一个也恰好被const标识符引用的地址,但两者之间没有编译时连接,因为constness仅适用于访问它的一种方法,即便如此,仅在这一功能的范围内。在某些情况下,它不能将非const指针视为const,而在其他情况下则不能将非const指针视为基于运行时状态的其他指针,这会以其他方式违反C ++的语义。