亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

C++ 和 Java 中引用賦值的區別

C++ 和 Java 中引用賦值的區別

慕妹3242003 2023-04-19 16:05:06
我已經學習 C++ 兩個星期了。在 Java 中,如果我們有兩個屬于同一個類的不同對象,并且如果我們將一個對象的引用分配給另一個對象的另一個引用,那么它們就指向同一個對象。之后,通過一個引用更改數據成員也會更改另一個引用中的數據成員。我的問題是:在 C++ 中不是也一樣嗎?我對復制構造函數和賦值運算符有點困惑。他們兩個都做深拷貝。沒有他們,據我所知,我們只能做淺拷貝。我也有一個代碼片段。#include <iostream>using namespace std;class Test{    int x;    int &ref;    public:        Test(int i):x(i), ref(x) {}        void print() { cout << ref;}        void setX(int i) {x = i;}        Test &operator = (const Test &t) {x = t.x; return *this;}};int main(){    Test t1(10);    Test t2(20);    t2 = t1;    t1.setX(40);    t2.print();  // This will print 10    cout << "\n\n";    t1.print();  // This will print 40    return 0;}
查看完整描述

5 回答

?
莫回無

TA貢獻1865條經驗 獲得超7個贊

看你的陳述:

我已經學習 C++ 兩個星期了。

祝賀你向前邁出了一大步。:-)

在 Java 中,如果我們有兩個屬于同一個類的不同對象,并且如果我們將一個對象的引用分配給另一個對象的另一個引用,那么它們就指向同一個對象。

這里的區別在于引用的定義。Java 稱為引用的 C++ 將稱為指針(因為它們始終指的是持續超出當前范圍的動態分配的對象)。盡管 Java 引用是智能的,并且當所有“Java 引用”都消失時對象被垃圾收集。因此,Java 引用更等同于std::shared_ptr<>.

// Java                       // C++

String s = new String("S");   std::shared_ptr<std::string> s = new std::string("S");

C++ 自動對象更像是 Java 的“值類型”(int/char/float)。不同之處在于,在 C++ 中,任何類型都可以充當“值類型”。


// Java                       // C++

int      x = 12;              int    x = 12;

                              Test   t1(10);  // acts like an int value

                                              // except destructor called

                                              // when it goes out of scope.

之后,通過一個引用更改數據成員也會更改另一個引用中的數據成員。

是的,基本上。但是你必須注意你的措辭。如果該成員是一個引用,那么您不會更改此成員(因為引用永遠不會更改它們在 C++ 中引用的內容),您正在更改引用所引用的對象。

// Java

class MyType  // forgive my syntax.

{

     public MyType() {x = new MyOtherType(); y = x}

     public MyOtherType x;

     public MyOtherType y;

};


MyType       a = new MyType();

MyOtherType  b = new MyOtherType();


a.x = b;


// Here both a.x and b refer to the same object.

// While a.y will refer to the original value.

// That is not how C++ will work (if you are thinking reference like

// like your description).



// C++

class MyType

{

     public:

         MyType() : x(), y(x) {}

         MyOtherType  x;

         MyOtherType& y;

          // Note   ^

};



MyType       a;

MyOtherType  b;


a.x = b;

我的問題是:在 C++ 中不是也一樣嗎?

不,因為引用不是對象。您需要將 Java 引用視為等同于 C++ std::shared_ptr。這就是我們在 C++ 中管理動態分配內存的方式。

我對復制構造函數和賦值運算符有點困惑。他們兩個都做深拷貝。沒有他們,據我所知,我們只能做淺拷貝。我也有一個代碼片段。

基本上是真的。它基本上允許您定義在將一個對象復制到另一個對象時賦值如何正確工作。

讓我們評論代碼。
您描述的輸出是我期望的輸出。

#include <iostream>
using namespace std;          // Please stop doing this.

測試

class Test

{

    int x;

    int &ref;


    public:

        Test(int i)

            : x(i)            // Set this->x = i

                              // Note X is an automatic object.

            , ref(x)          // Set this->ref as an alias for this->x

                              // Note1: This can never be undone.

                              // Note2: Changing ref will always change x

                              //        conversely changing x will be

                              //        visible via ref.

                              // Note3: ref can **not** be made to reference

                              //        another object.

        {}

        void print()

        {

            cout << ref;      // Prints what this->ref is a reference too:

                              // Looking at the constructor its this->x

        }

        void setX(int i)

        {

            x = i;            // Modifies this->x

                              // This is visible via this->ref

        }

        Test &operator = (const Test &t)

        {

            x = t.x;          // Copies the value from t.x into this->x

                              // Note1: this->ref and t.ref continue to refer

                              //        to their origin objects.

                              // Note2: since this->x has changed

                              //        this change is visible in this->ref

            return *this;

        }

};

主要的

int main()

{

    Test t1(10);                  // t1.x = 10 t1.ref = t1.x

    Test t2(20);                  // t2.x = 20 t2.ref = t2.x

    t2 = t1;                      // Assignment operator above called.

                                  // t2.x = 10 t2.ref = t2.x


    t1.setX(40);                  // Call the setX method on t1

                                  // t1.x = 40 t1.ref = t1.x


    t2.print();                   // Call the print method on t2

                                  // This prints t2.ref to the output.

                                  // t2.ref is a reference to t2.x

                                  // So we print the value t2.x

                                  // Should print 10


    cout << "\n\n";


    t1.print();                   // Call the print method on t1

                                  // This prints t1.ref to the output.

                                  // t1.ref is a reference to t1.x

                                  // So we print the value t1.x

                                  // Should print 40


    return 0;

}


查看完整回答
反對 回復 2023-04-19
?
富國滬深

TA貢獻1790條經驗 獲得超9個贊

在 Java 中,如果我們有兩個屬于同一個類的不同對象,并且如果我們將一個對象的引用分配給另一個對象的另一個引用,那么它們就指向同一個對象。

我的問題是:在 C++ 中不是也一樣嗎?

這根本不一樣。在 C++ 中,不能重新分配引用以引用另一個對象。他們在整個生命周期中都指代同一個對象。將賦值操作應用于引用時,將對引用的對象進行賦值。

請注意,Java 沒有顯式引用。所有類類型變量都是引用,原始變量是值對象。C++是不同的。您必須明確指定變量是引用還是對象,并且您可以擁有類類型的值對象以及對基本類型的引用。

在某些方面,Java 引用比 C++ 引用更類似于 C++ 指針。特別是,指針可以為空,并且可以賦值指向別處,就像 Java 引用一樣。

// Java

int i = 0;             // not a reference

i = some_int;          // i is modified

Test tref = null;      // a reference

tref = t;              // reference is modified

tref = other_t;        // reference is modified; t is not modified


// C++

Test t;                // not a reference

Test& tref = t;        // a reference

t = other_t;           // t is modified

tref = other_t;        // t is modified; reference is not


Test* tptr = nullptr;  // a pointer (not a reference)

tptr = &t;             // tptr is modified

*tptr = other_t;       // t is modified

tptr = other_t;        // tptr is modified; t is not modified


查看完整回答
反對 回復 2023-04-19
?
qq_花開花謝_0

TA貢獻1835條經驗 獲得超7個贊

創建t2實例時,t2.ref初始化為引用t2.x

Test(int i):x(i), ref(x) {}

后者,

t2 = t1;

不會改變t2.ref所指的內容(因為它是無效的:在 C++ 中,引用不能綁定到新的引用對象):

Test &operator = (const Test &t) {x = t.x; return *this;}

t2.ref仍然指的是t2.x,您永遠不會改變其價值:

t1.setX(40);



查看完整回答
反對 回復 2023-04-19
?
有只小跳蛙

TA貢獻1824條經驗 獲得超8個贊

在他關于 C++ 的書中,Stroustrup 對此進行了解釋:


請注意,這兩個對象是獨立的。我們可以改變 y 的值而不影響 x 的值。例如 x=99 不會改變 y 的值。與 Java、C# 和其他語言不同,但與 C 一樣,這適用于所有類型,而不僅僅是整數。如果我們希望不同的對象引用相同的(共享的)值,我們必須這樣說。我們可以使用指針:


int x = 2;

int y = 3;

int? p = &x;

int? q = &y; // now p!=q and *p!=*q

p = q; // p becomes &y; now p==q, so (obviously)*p == *q

http://img1.sycdn.imooc.com//643fa10d0001a30105160103.jpg

我隨意選擇了 88 和 92 作為 int 的地址。同樣,我們可以看到被賦值對象從被賦值對象獲取值,產生兩個具有相同值的獨立對象(此處為指針)。也就是說,p=q 給出 p==q。p=q之后,兩個指針都指向y。引用和指針都引用/指向一個對象,并且都在內存中表示為機器地址。但是,使用它們的語言規則不同。對引用的賦值不會改變引用所指的內容,而是將其賦值給被引用的對象:


int x = 2;

int y = 3;

int& r = x; // r refers to x

int& r2 = y; // now r2 refers to y

r = r2; // read through r2, write through r: x becomes 3


查看完整回答
反對 回復 2023-04-19
?
SMILET

TA貢獻1796條經驗 獲得超4個贊

在 Java 中,您有兩種對象:那些始終按值傳遞的對象,它們完全是本機數據類型:int、long、double,...和非本機對象,隱式繼承自 ,它們存儲在變量中Object作為引用并在賦值時傳遞(例如傳遞給其他變量或函數參數)。

在 C++ 中,任何數據類型都可以顯示兩種類型的行為,按值傳遞或按引用傳遞。而在 C++ 中,您必須明確說明。

在 C++ 中,您可以通過三種方式傳遞對象,而不僅僅是兩種:

  • 按價值

  • 引用

  • 通過指針

與 C++ 引用相比,Java 引用更接近于 C++ 指針:您可以將指針重新分配給不同的對象,但不能為引用這樣做。它有助于將 C++ 引用視為具體對象的別名(另一個名稱),忽略在某些情況下這可能真的適用(然后根本沒有分配內存)而在其他情況下(尤其是函數參數)則不然。

現在準確地說:即使在 Java 中,每個變量都會被復制,甚至是引用變量。但是對于后者,復制的只是引用本身,而不是對象!所以要顯示相似之處:

// Java? ? ? ? ? ? ? ? ? ? ? ? ?// C++


int n = 10;? ? ? ? ? ? ? ? ? ? ?int n = 10;

String s = "hello";? ? ? ? ? ? ?std::string* s = new std::string("hello");


f(n, s);? ? ? ? ? ? ? ? ? ? ? ? f(n, s);

voidf(int n, String s)? ? ? ? ? void f(int n, std::string* s)

{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?{

? ? n = 12;? ? ? ? ? ? ? ? ? ? ? ? ? n = 12; // in both cases, only local variable changed

? ? s += "ads";? ? ? ? ? ? ? ? ? ? ?*s += "ads";

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //? ^ solely: special syntax for pointers!

? ? s = "world";? ? ? ? ? ? ? ? ? ? s = new std::string("world");

? ?// now s refers/points to another object in both cases

}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}

到目前為止應該知道......老實說,上面簡化了太多:在 Java 中,我們有自動垃圾收集,在 C++ 中,我們沒有。所以實際上,上面在 C++ 中創建的字符串對象再也沒有被清理過,我們有內存泄漏!現代 C++ 引入了智能指針來解決這個問題,同時考慮 Java 中的垃圾回收,C++ 代碼可能看起來像:


int n;

std::shared_ptr<std::string> s = std::make_shared("hello");

f(n, s);


void f(int n, std::shared_ptr<std::string> s)

{

? ? n = 12;

? ? *s += "ads";

? ? s = std::make_shared("world");

}

std::shared_ptrJava中的所有引用計數都隱藏在基類中的哪里Object......


與 Java 不同的是,您也可以按值傳遞字符串:


void f(int, std::string s);

現在字符串將被復制到局部變量中,就像 int 一樣。唯獨:怎么???


這就是復制構造函數發揮作用的地方。如果您愿意,它是如何創建該副本的秘訣,即如何將內部表示復制到新對象中。對于 a std::string,這將是一些內部的、動態分配的數組,其中包含字符串的內容、其當前容量(即數組的總長度)和大?。▽嶋H占用了多少數組)。


最后是 C++ 參考:


void f(int, std::string& s);

在這種情況下, s 將始終引用分配給該函數的對象,您不能更改引用(至少在法律上是這樣,在某些情況下您可以使用一些非常骯臟的黑客...),只能更改引用的對象。


實際上,在 C++ 中,問題更復雜:


在 Java 中,您可以獲得自動內存管理,有一個垃圾收集器選擇所有不再被引用的對象。這種事情在 C++ 中不存在,我們需要手動清理。實際上,我在上面的示例中創建的字符串根本沒有被清理,所以我們發生了內存泄漏!??!


查看完整回答
反對 回復 2023-04-19
  • 5 回答
  • 0 關注
  • 186 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號