常量引用行为 - 为什么会出现此输出

const reference behaviour - why this output?

本文关键字:输出 为什么 引用 常量      更新时间:2023-10-16

我不清楚以下输出。为什么在第一种情况下输出是:Joni Gallo,而在第二种情况下(在我只更改一行之后(,输出是:Jonlo

输出:

// classes and default constructors
#include <iostream>
#include <string>
using namespace std;
class Example3 {
    string data;
  public:
        Example3 (const string& str) 
        {
            data = str;
           // data.erase(3,5);
        }
    Example3() {}
    void doit()
    {
    data.erase(3,5);
    }
    const string& content() const {return data;}
};
int main () {
  Example3 foo("Joni Gallo");
  Example3 bar (foo);
  bar.doit();
  cout << "content: " << foo.content() << 'n';
  return 0;
}

Joni Gallo,而输出:

// classes and default constructors
#include <iostream>
#include <string>
using namespace std;
class Example3 {
    string data;
  public:
        Example3 (const string& str) 
        {
            data = str;
            data.erase(3,5);
        }
    Example3() {}
    void doit()
    {
   // data.erase(3,5);
    }
    const string& content() const {return data;}
};
int main () {
  Example3 foo("Joni Gallo");
  Example3 bar (foo);
  bar.doit();
  cout << "content: " << foo.content() << 'n';
  return 0;
}

是:Jonlo

?为什么?为什么擦除在第二种情况下影响原始对象,而不是在第一种情况下影响

PS 另外,在构造函数中传递const string& str然后将其分配给成员变量是什么意思 - 这是否意味着每次我更改成员变量内容时,原始对象内容(其引用已传递给构造函数(也将更改?(就像指针一样(

首先请注意,即使您通过引用传递字符串以进行构造,您也没有将其声明为类的成员。因此,每个类实例都有自己的字符串。将引用分配给非引用变量时,将创建副本。如果随后更改非引用副本(此处为数据成员变量(,则不会更改引用。

在第一个程序中,在 doit 成员函数中编辑数据成员。在第二个中,您可以在构造函数中执行此操作。

第一个程序:

  • foo是用"Joni Gallo"设置为数据构建的。
  • 酒吧由FOO建造。所以它也有"Joni Gallo"作为数据。
  • 现在你可以用酒吧做任何你想做的事情。它不会改变foo的数据。
  • 所以结果还是"乔尼·加洛">

第二个程序:

  • foo由"Joni Gallo"构造,擦除操作从长度为5的位置3中删除。所以foo的数据成员是"Jonlo"。
  • 同样,酒吧发生的任何情况都不会改变 foo 的数据成员。
  • 所以结果是"Jonlo"。

总之,您观察到的结果与 foo 的成员因引用而被修改无关。您可能错过了该结构会影响foo和bar。

在第一个示例中,您更改bar实例,因此foo保持不变,内容是您在构造函数中输入的内容。

在构造函数内部的第二种情况下Example3您执行一些反映在 foo 中的更改。它们是不同的对象,因此对一个对象的修改不会影响另一个对象。

区别在于data.erase的时间:在第二种情况下,它是在foo的构造函数中完成的,然后修改后的字符串由复制构造函数复制到bar。即使您注释掉bar声明和对doIt的调用(无论如何都是无操作(,也会打印相同的修改字符串。

然而,在第一种情况下,foodata根本没有进行擦除,因此原始字符串被打印出来。同样,bar的声明和对doIt的调用可以得到评论,因为foodatabar的脱节。

全局

string data;

是一个字符串。不是对字符串的引用或指向字符串的指针。将复制分配给数据的任何字符串。

data = string:复制。

data = string reference:复制。

data = string pointer:编译器错误。

data = char array:复制。

data = char pointer:复制。

假设字符数组和字符指针已正确终止。如果没有,则为未定义的行为。

来源 1:

Example3 foo("Joni Gallo");

foo副本提供字符串foo.data = "Joni Gallo"。

Example3 bar (foo);

做酒吧。Bar 复制 foo,因此它获取源字符串的 foo 副本的副本。bar.data = "Joni Gallo"。

bar.doit();

擦除 bar 字符串副本的一部分。 bar.data = "Jonlo"。

cout << "bar's content: " << foo.content() << 'n';

是谎言。这将打印出 foo 的字符串副本。

来源 2:

Example3 foo("Joni Gallo");

foo.foo复制提供的字符串并擦除副本的一部分。 foo.data = "Jonlo"。

Example3 bar (foo);

做酒吧。Bar 复制 foo,因此它获取 foo 编辑的源字符串副本的副本。bar.data = "Jonlo"。

bar.doit();

什么都不做。 bar.data = "Jonlo"。

cout << "bar's content: " << foo.content() << 'n';

仍然是谎言,但这次 foo 的副本和 Bar 的副本将是相同的。