为什么函数不能更改其参数对象的 address/reference 值?
Why can't a function change its argument object's address/reference value?
我了解到 Java 和 C,you can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
由于 C++ 的引用传递特性,我认为我可以在 C++ 中看到不同的行为,但我的代码似乎与上述声明一致...
void reassign(string & a);
int main()
{
string x = "abcd";
cout <<"x is " << x <<" at " << &x <<endl; //"x is abcd at 0x7bc7ebd5b720"
reassign(x);
cout <<"x is " << x <<" at " << &x <<endl; //"x is efgh at 0x7bc7ebd5b720"
}
void reassign(string & a)
{
a = string("efgh");
}
既然"string()"构造了一个新的字符串,为什么"reassign"函数不改变原字符串的地址?
一旦分配了一个对象,就不能再改变它的地址了。您可以更改其内容(这是您的程序所做的),但地址在对象的生命周期内将保持不变。
如果您使用 new
动态创建对象,则可以将不同的对象分配给同一个指针。但是,规则将保持不变:旧对象的地址不会改变,但您可以将新对象分配给旧指针。
void reassign(string* & a);
int main() {
string *x = new string("abcd");
cout <<"x is " << *x <<" at " << x <<endl; //"x is abcd at 0x95b7008"
reassign(x);
cout <<"x is " << *x <<" at " << x <<endl; //"x is efgh at 0x95b7030"
delete x;
return 0;
}
void reassign(string* & a) {
string *old = a;
a = new string("efgh");
delete old;
}
你糊涂了,因为你的类比不对。 Java中没有"argument object"这样的东西,因为"objects"本身不是Java中的值([=46=中没有"object types" ]). Java 中仅有的类型是原始类型和引用类型,其中 "references" 是指向对象的指针。所以在Java中你只能有指向对象的指针作为变量或参数的值,你只能通过指向对象的指针来处理对象。
"you cannot change where that pointer points" 是 按值传递 的结果。 Java 始终按值传递,这意味着对参数的赋值不能更改传递变量的 value。请记住,变量只能是原始类型或引用类型。这里你说的是引用类型。所以引用类型变量的"value"就是引用(指向对象的指针),即它所指向的对象的地址。因此,您无法更改该值意味着您无法更改指针指向的位置。
例如,在 Java 你可能有这样的东西:
public static void reassign(String a) {
a = new String("efgh");
}
public static void main(String[] args) {
String x = "abcd";
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
reassign(x);
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
}
这里,main
中的x
是指向对象的指针。 reassign
中的a
也是指向对象的指针。分配给 reassign
中的指针参数 a
对传递的指针变量 x
没有影响(即它不影响指针指向的位置),因为它是按值传递。
上述代码在 C++ 中的等价物如下所示:
void reassign(string *a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
return 0;
}
除了上面所示的按值传递之外,C++ 还具有按引用传递,其中对参数的赋值与对调用作用域中传递的变量赋值具有相同的效果。这是与上面完全相同的东西,但带有传递引用:
void reassign(string *&a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x8673008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is efgh at 0x8673030
return 0;
}
请注意,在 none 的情况下,我们 更改了 指向的对象。我们只是简单地创建了一个新对象,并试图改变指针指向这个对象。旧对象仍然没有改变。改变一个对象的能力是一个独立于传值和传引用的正交问题,所以我们在这里不做讨论。
我了解到 Java 和 C,you can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, you cannot change where that pointer points.
由于 C++ 的引用传递特性,我认为我可以在 C++ 中看到不同的行为,但我的代码似乎与上述声明一致...
void reassign(string & a);
int main()
{
string x = "abcd";
cout <<"x is " << x <<" at " << &x <<endl; //"x is abcd at 0x7bc7ebd5b720"
reassign(x);
cout <<"x is " << x <<" at " << &x <<endl; //"x is efgh at 0x7bc7ebd5b720"
}
void reassign(string & a)
{
a = string("efgh");
}
既然"string()"构造了一个新的字符串,为什么"reassign"函数不改变原字符串的地址?
一旦分配了一个对象,就不能再改变它的地址了。您可以更改其内容(这是您的程序所做的),但地址在对象的生命周期内将保持不变。
如果您使用 new
动态创建对象,则可以将不同的对象分配给同一个指针。但是,规则将保持不变:旧对象的地址不会改变,但您可以将新对象分配给旧指针。
void reassign(string* & a);
int main() {
string *x = new string("abcd");
cout <<"x is " << *x <<" at " << x <<endl; //"x is abcd at 0x95b7008"
reassign(x);
cout <<"x is " << *x <<" at " << x <<endl; //"x is efgh at 0x95b7030"
delete x;
return 0;
}
void reassign(string* & a) {
string *old = a;
a = new string("efgh");
delete old;
}
你糊涂了,因为你的类比不对。 Java中没有"argument object"这样的东西,因为"objects"本身不是Java中的值([=46=中没有"object types" ]). Java 中仅有的类型是原始类型和引用类型,其中 "references" 是指向对象的指针。所以在Java中你只能有指向对象的指针作为变量或参数的值,你只能通过指向对象的指针来处理对象。
"you cannot change where that pointer points" 是 按值传递 的结果。 Java 始终按值传递,这意味着对参数的赋值不能更改传递变量的 value。请记住,变量只能是原始类型或引用类型。这里你说的是引用类型。所以引用类型变量的"value"就是引用(指向对象的指针),即它所指向的对象的地址。因此,您无法更改该值意味着您无法更改指针指向的位置。
例如,在 Java 你可能有这样的东西:
public static void reassign(String a) {
a = new String("efgh");
}
public static void main(String[] args) {
String x = "abcd";
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
reassign(x);
System.out.printf("x is %s at %x\n", x, System.identityHashCode(x)); // x is abcd at 25154f
}
这里,main
中的x
是指向对象的指针。 reassign
中的a
也是指向对象的指针。分配给 reassign
中的指针参数 a
对传递的指针变量 x
没有影响(即它不影响指针指向的位置),因为它是按值传递。
上述代码在 C++ 中的等价物如下所示:
void reassign(string *a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x82b1008
return 0;
}
除了上面所示的按值传递之外,C++ 还具有按引用传递,其中对参数的赋值与对调用作用域中传递的变量赋值具有相同的效果。这是与上面完全相同的东西,但带有传递引用:
void reassign(string *&a) {
a = new string("efgh");
}
int main() {
string *x = new string("abcd");
cout << "x is " << *x <<" at " << x << endl; // x is abcd at 0x8673008
reassign(x);
cout << "x is " << *x <<" at " << x << endl; // x is efgh at 0x8673030
return 0;
}
请注意,在 none 的情况下,我们 更改了 指向的对象。我们只是简单地创建了一个新对象,并试图改变指针指向这个对象。旧对象仍然没有改变。改变一个对象的能力是一个独立于传值和传引用的正交问题,所以我们在这里不做讨论。