C++ 为什么会发生这种情况?

C++ 为什么会发生这种情况?,c++,constants,C++,Constants,给定以下代码: 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)

给定以下代码:

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;
}
产生以下结果:

B
M


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

指针别名。通过将
ItemCopy::Ptr
赋给
this->Ptr
可以将指针别名化,并通过它赋给另一个值。写这样的东西时也要记住。因为
ItemCopy
是常量,
ItemCopy.Ptr
具有有效类型的
char*const
。指针为常量,但指向的项可以修改。这意味着任务:

*ItemCopy.Ptr = 'M';

是有意义且允许的(基础对象本身不是
const
),复制指针并通过它进行赋值也是合法的。直接赋值
ItemCopy.Temp='M'
是不合法的,但这并不意味着您不能修改变量
ItemCopy.Temp
,如果您有另一个非
const
访问路径。

Ptr
指向
ItemCopy.Ptr
,这反过来又指向
Temp
。因此,当您取消引用它时,您将写入
Temp

的语义:

    const TestA &ItemCopy

只能保证指针成员ItemCopy.Temp本身不能直接修改,指针指向的对象不能保证常量。

这是因为编译时应用了
const
规则,但这种规避是运行时状态的结果。创建常量引用对象成员的非常量副本不会修改该对象,因此不会违反常量引用。这是因为据编译器所知,您所做的只是复制一个值,即一段mememory的地址。它不会预测您可能在这里或其他地方取消引用它-它不会将常量应用于内存位置,而是应用于标识符,您还没有违反这一点


在运行时,您为非const ptr分配一个地址,该地址恰好也由const标识符引用,但两者之间没有编译时连接,因为constanss仅适用于访问它的一种方式,甚至仅适用于这一函数的作用域。在某些情况下,它不能将非const指针视为const,而不能基于运行时状态来处理其他非const,否则将违反C++的其他语义。你不是,我认为这是不确定的行为。C++中的一些规则更像是建议,如果你想要的话,你可以避开。好的或更坏的。(我不认为是,但你可能发现了一些我没有发现的东西。)@Anders K:不完全是。它们更像是路标,告诉你路的尽头。驱车离开公路不是违法的,它只是意味着你不再在路途上的约束和保证下工作(比如你不会突然从悬崖上驶过),或者“你面前不会有任何突然的树”。违反C++规则,你就走了。这不是违法的。你的程序不再是C++,你不能假设程序的任何部分都会像C++那样。这是一个很好的比喻,真的。你的评论应该被wiki化或者其他方式传给下一代。链接到的内容会很有帮助。请注意,这纯粹是一个示例类,用于演示发生了什么。函数()是这样的,Temp1的状态与Temp2不同。在赋值过程中,有没有办法使它变为const char*const?@SSight3:您可以使成员变量
const char*
,但我认为您的示例是一个人工演示。你想实现一些具体的目标吗?我看不出有什么理由让一个成员变量指向同一类实例中的另一个成员变量,而将其公开几乎肯定是一个糟糕的设计。这是人为的。在构建一个合适的类之前,我正在测试假设,只是想确保我知道尽可能多的选项。