【问题标题】:Why the need for both const reference and const member function?为什么需要 const 引用和 const 成员函数?
【发布时间】:2020-06-17 18:56:42
【问题描述】:

我正在做“使用 C++ 的编程原理和实践”中的练习 我找到了一个有这个成员函数here的类:

const vector<string> &get_name() const { return name; }

其中名称是一个向量:vector&lt; string&gt; name;

到目前为止,本书介绍了 2 个概念(最多 235 页):

  1. 返回一个const引用,防止函数改变返回值:

    const vector<string> &get_name() { return name; } 
    
  2. 一个不能修改对象的 const 成员函数。在这种情况下,它会是这样的:

    vector<string> get_name() const { return name; } 
    

也许我没有完全理解这一点,但这两个概念不一样吗? 不想更改“名称”向量。

为什么需要两个“const”?

感谢任何花时间回复的人!

【问题讨论】:

  • 它们不一样,因为第二个版本必须制作name 的(可能很昂贵)副本。
  • First const 仅适用于返回的对象,不能在 const 实例/对象上调用该方法。第二个适用于实例/对象,因此 const/non-const 实例都可以调用该方法。
  • 第一个说“你不能改变你要求的东西,我可能会在你要求的时候改变”,第二个说“如果你求这个东西,你可以用我给你的东西做任何你想做的事”。这些不是同一个概念。

标签: c++ member-functions const-reference


【解决方案1】:
  1. 返回一个const引用,防止函数改变返回值
  2. 无法修改对象的 const 成员函数。在这种情况下,它会是这样的

这可能更清楚一点,我会尝试更好地解释它。

返回一个 const 引用可以防止 返回的对象调用者改变。

这是一个例子:

// let get_name be `const std::vector<std::string>& get_name()`

np1.get_name().size(); // ok, size is a const function of vector
np1.get_name().push_back("hello"); // ERROR! push_back is not a const function of vector

确实,调用者无法更改name 向量。返回类型是 const 限定的。

但是,如果函数 get_name 本身不是 const 限定的(不是返回类型),则允许从类本身更改名称。

你看,成员函数接收一个隐藏的this 参数,它是一个指向被调用对象的指针。指针既可以指向一个 const 对象,也可以指向一个可变对象。这是比较:

// returning const ref, callers cannot change the name vector
const std::vector<std::string>& get_name() {
    // The function receive a `this` that points to a mutable,
    // we can change the name from the inside
    this->name.push_back("another");
    return name;
}

// the `this` pointer points to const -----v---v
const std::vector<std::string>& get_name() const {
    this->name.push_back("another"); // ERROR! Cannot mutate member of const object
    return name;
}

Const 限定的成员函数对调用者非常有用,因为它知道无论何时调用此函数,其状态都不会改变。

例如,不仅您知道vector::size() 函数不会改变向量,而且编译器也保证它是一个 const 限定的成员函数。

最后一点,您在此处发布的代码:

vector<string> get_name() const { return name; } 

这不会返回引用,但会复制。调用者可以随心所欲地改变副本,但不能改变 name 本身。

这是一个变异的副本示例:

auto name_copy = np1.get_name();

name_copy.push_back("another name"); // works, we mutated the copy by adding an element

【讨论】:

  • 非常感谢,纪尧姆!它真的很有帮助。如果我可能会问另一个问题,您如何更改最后一行的副本:vector get_name() const { return name; }
  • 你能看看我的代码吗? github.com/ltr01/PPPCpp-Tests/blob/master/9.3_test2.cpp 我在您的示例中定义了函数 get_name1()、get_name2() 和 get_name3()。函数 1 和 2 的行为就像你说的那样。但是在创建对象 np3 并向其添加另一个元素之后,我仍然看不到那个新元素。我做错了什么或者我仍然没有得到什么?非常感谢您抽出宝贵的时间!真的很有帮助。
  • @Theodore 你将无法使用get_name3() 改变name。由于您返回一个副本,因此您所做的任何更改(例如 push_back)都将在副本上完成,而不是在原始 name 对象上完成。如果您想要可变访问,请使用std::vector&lt;std::string&gt;&amp; get_name()。由于返回的引用是非常量的,因此您将能够改变被引用的对象。
  • 我终于成功地在函数 get_name3() 内推回了一个副本。那是我做不到的。我通过改变引用的对象来理解你的意思。哇,自从 24 小时前,我明白了很多!非常感谢,纪尧姆!
【解决方案2】:

一个成员函数有一个隐含的this-reference。

并且引用的对象可以是const-qualified,允许在常量对象上调用成员函数,方法是在声明中的参数列表后面加上const

该成员函数是否还返回对某些常量数据的引用可能是强相关的,但仍完全由程序员决定。

【讨论】:

    【解决方案3】:

    这种情况返回一个对vector&lt;string&gt; 的常量引用,我们不能更改这个向量。但是我们可以在这个函数中改变vector&lt;string&gt; name

    const vector<string> &get_name() { return name; } 
    

    在这种情况下,返回vector&lt;string&gt; 的副本,我们可以更改这个向量,因为它已经是另一个向量。在这个函数中我们不能改变vector&lt;string&gt; name

    vector<string> get_name() const { return name; } 
    

    【讨论】:

      猜你喜欢
      • 2017-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-10
      • 1970-01-01
      • 2011-06-04
      相关资源
      最近更新 更多