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

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

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

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
我隨意選擇了 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

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++ 中不存在,我們需要手動清理。實際上,我在上面的示例中創建的字符串根本沒有被清理,所以我們發生了內存泄漏!??!
添加回答
舉報