以下输出对我来说并不清楚。为什么在第一种情况下输出是: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
然后将其分配给成员变量意味着 - 这是否意味着每当我更改成员变量内容时,原始对象内容(其引用被传递给构造函数)也将是改变了吗? (就像指针一样)
答案 0 :(得分:4)
首先请注意,即使您通过引用传递字符串进行构造,您也可以在没有引用的情况下将其声明为类的成员。所以每个类实例都有自己的字符串。为非引用变量分配引用时,将生成副本。如果您随后更改了非引用副本(此处为您的数据成员变量),则不会更改引用。
在第一个程序中,您可以在doit成员函数中编辑数据成员。在第二个中,您可以在构造函数中执行此操作。
第一个程序:
第二个程序:
总之,您观察到的结果与foo的成员因参考而被修改无关。你可能错过了这个结构会影响foo和bar。
答案 1 :(得分:2)
在您的第一个示例中,您更改了bar
实例,因此foo
保持不变,内容就是您在构造函数中放置的内容。
在Example3
构造函数中的第二种情况下,您执行了foo
中反映的一些更改。它们是不同的对象,所以修改一个不会影响另一个。
答案 2 :(得分:2)
区别在于data.erase
的时间:在第二种情况下,它是在foo
的构造函数中完成的,然后修改后的字符串被复制构造函数复制到bar
。即使您注释掉bar
的声明以及对doIt
的调用(无论如何都是无操作),也会打印相同的修改后的字符串。
然而,在第一种情况下,根本没有对foo
的{{1}}进行删除,因此打印原始字符串。同样,data
的声明和对bar
的调用可以得到评论,因为doIt
的{{1}}与foo
的{{1}}断开连接。
答案 3 :(得分:1)
全局
string data;
是一个字符串。不是对字符串或指向字符串的指针的引用。将复制分配给数据的任何字符串。
data = string
:复制。
data = string reference
:复制。
data = string pointer
:编译错误。
data = char array
:复制。
data = char pointer
:复制。
假设char数组和char指针正确终止。如果没有,则定义不明确的行为。
Example3 foo("Joni Gallo");
让foo。 foo复制提供的字符串foo.data =&#34; Joni Gallo&#34;。
Example3 bar (foo);
做吧。 Bar复制foo,因此它获得了foo的源字符串副本的副本。 bar.data =&#34; Joni Gallo&#34;。
bar.doit();
删除部分栏的字符串副本。 bar.data =&#34; Jonlo&#34;。
cout << "bar's content: " << foo.content() << '\n';
是一个谎言。这打印出foo的字符串副本。
Example3 foo("Joni Gallo");
让foo。 foo复制提供的字符串并删除部分副本。 foo.data =&#34; Jonlo&#34;。
Example3 bar (foo);
做吧。 Bar复制foo,因此它获得了foo编辑的源字符串副本的副本。 bar.data =&#34; Jonlo&#34;。
bar.doit();
什么都不做。 bar.data =&#34; Jonlo&#34;。
cout << "bar's content: " << foo.content() << '\n';
仍然是谎言,但这次foo的副本和Bar的副本将是相同的。