给出以下代码:
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。为什么我被允许间接修改它甚至取指针的非常量副本?
答案 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 ++的语义。