为什么函数不能改变其参数对象的地址/参考值?

时间:2015-05-20 19:16:48

标签: c++ reference parameter-passing pass-by-reference

我在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 ++中看到不同的行为,但我的代码似乎同意上述声明......

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");
}

因为&#34; string()&#34;构造一个新的字符串,为什么不重新分配&#34;功能改变原始字符串的地址?

2 个答案:

答案 0 :(得分:6)

一旦分配了一个对象,就没有什么可以改变它的地址。您可以更改其内容(这是您的程序所做的),但地址将在对象的生命周期内保持不变。

如果使用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;
}

Demo.

答案 1 :(得分:0)

你很困惑因为你的比喻不对。在Java中,没有“参数对象”这样的东西,因为“对象”本身不是Java中的值(Java中没有“对象类型”)。 Java中唯一的类型是基本类型和引用类型,其中“引用”是指向对象的指针。因此在Java中,您只能将对象指针作为变量或参数的值,并且只能通过指向对象的指针来处理对象。

“你无法改变指针指向的位置”是按值传递的结果。 Java始终是按值传递,这意味着对参数的赋值不能更改传递的变量的。请记住,变量只能是基本类型或引用类型。在这里,您谈论的是参考类型。因此,引用类型变量的“值”是引用(指向对象的指针),即它指向的对象的地址。因此,您无法更改值意味着您无法更改指针指向的位置。

例如,在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
}

此处,x中的main是指向对象的指针。 a中的reassign也是指向对象的指针。分配给a中的指针参数reassign对传递的指针变量x没有影响(即它不会影响指针指向的位置),因为它是传值的。 / p>

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;
}

除了上面显示的pass-by-value之外,C ++还具有pass-by-reference,其中对参数的赋值与分配给调用范围中的传递变量具有相同的效果。这与上面完全相同,但是通过引用传递:

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;
}

请注意,在这里没有任何情况下我们更改指向的对象。我们只是创建了一个新对象,并尝试将指针更改为指向此对象。旧对象仍然没有改变。改变对象的能力是一个独立的,正交的问题,从传值和传递引用,所以我们不在这里讨论它。