【问题标题】:Class field modifiable inside a const method if field passed by reference?如果字段通过引用传递,类字段可在 const 方法内修改?
【发布时间】:2018-05-09 08:39:11
【问题描述】:

这里是 C++ 学生:

今天,在写一个类时,我注意到我可以使用 const 方法修改一个非可变字段,如果该字段是通过引用传递的:

class Foo {

public:
    void func1(int & _n) const { _n = 42; }
    void func2() { func1(n); }

private:
    int n;
};

int main() {
    Foo foo;
    foo.func2();

    return EXIT_SUCCESS;
}

我知道这是可能的,因为 const 方法只是使用 this 到 const,但如果我将字段作为引用传递,我可以直接访问它没有经过this(我还在学习,英语还不是很好,我可能说错了);

所以,我的问题是:

如果可以通过简单的“技巧”修改非可变字段,那么 const 方法的真正用途是什么?

谢谢!

【问题讨论】:

  • 不要发布代码截图。邮政编码。

标签: c++ methods reference this


【解决方案1】:

我能够修改非可变字段

无法修改非可变字段,因为该字段不是不可变的。尝试将n 声明为const,您将看到代码将不再编译,并且没有任何技巧(除了滥用const_cast 和调用未定义的行为)将使其编译。

您的代码中唯一的constfunc1,它将函数中的“不可见”Foo* const this(指向可修改Foo 的不可修改指针)变成Foo const* const this(不可修改指向不可修改的Foo)。

事实证明,这两个虚构的consts 完全按照设计工作,因为以下两种尝试都将失败:

  • this = nullptr; // won't compile
  • this->n = 42; // won't compile

然而,这两个consts 都与_n 参数无关。 _nthis->n 引用同一个 int 对象,但只有两者中的后者将其视为 const

这导致了一个重要的发现。拥有const 引用或指向某事物的指针和拥有指向不可变类型的引用或指针是两件不同的事情。 int 是可变的,所以只要你有一个非const 引用或指向一个的指针,修改都是可能的,无论程序的其他部分是否将int 对象视为const

如果非可变字段可以,那么 const 方法的真正用途是什么? 用一个简单的“技巧”来修改?

正如我上面所说,字段本身不是不可变的。而且,如果您需要一个“技巧”来关闭编译器,那么无论如何您只是在碰运气。

【讨论】:

    【解决方案2】:

    只需定义const Foo foo; 而不是Foo foo;,编译器就会捕捉到错误并再次成为你的朋友。

    【讨论】:

      【解决方案3】:

      const 方法的真正用途是什么

      它允许您让编译器维护类不变量。但是编译器不会保护你免于被自己踢到脚。在 const 成员函数内部,编译器只会阻止通过名称修改类成员。

      如果您从外部传递对数据的引用,那么它就在您身上。不会发出任何复杂的代码来验证您没有传递对成员的引用。

      访问修饰符也是如此。他们只会阻止访问成员的姓名。您可以通过多种方式破坏该封装,编译器不会打扰您。

      该语言具有保护您免受墨菲(而不是马基雅维利)侵害的机制。如果您使用“技巧”并违背语言的本质,它们将无济于事。适当的封装取决于程序员,而不是编译器。

      【讨论】:

      • 我正在寻找的答案。谢谢!
      【解决方案4】:

      在现实世界中,您不会公开访问内部类成员。当你这样做时,所有的赌注都被取消了。

      Const 方法可帮助您强制封装类,但您首先需要进行这种封装 - 通过将私有数据标记为私有。

      【讨论】:

      • 哦,抱歉,我知道,但是私有字段仍然存在问题,只需在另一个字段中调用该方法即可。
      • 编译器不允许你从 const 调用非 const 方法 - 试试吧。
      • 好的,但我还是不明白:我仍然可以从非常量方法调用 func(),这样我就可以直接将私有 n 字段传递给它...?
      • 你可以,但你不会,因为 func 已经有 (const) 访问 n。请理解 const 方法可以防止偶然的错误,但没有什么可以阻止您故意破坏保护。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多