[英]Overloading assignment operator in polymorphic classes
我來自Java,因此請多多包涵。 我讀過其他幾篇文章,但似乎找不到答案。
我有一個如下所示的基類(Obj)頭文件。
class Obj {
public:
Obj();
Obj(int);
int testInt;
virtual bool worked();
Obj & operator = (const Obj & other) {
if(this != &other) {
//other.testInt = this->testInt;
return *this;
}
}
};
基類
Obj::Obj() {
}
Obj::Obj(int test) {
this->testInt = test;
}
bool Obj::worked() {
return false;
}
這是子類標題
class Obj1 : public Obj {
public:
Obj1();
Obj1(int);
virtual bool worked();
};
兒童班
#include "Obj1.h"
Obj1::Obj1() {
}
Obj1::Obj1(int a) {
this->testInt = a / 2;
}
bool Obj1::worked() {
return true;
}
這是我的主班
int main() {
Obj obj = Obj(99);
Obj1 obj1 = Obj1(45);
obj = obj1;
if(obj.worked())
cout << "good" << obj.testInt << endl;
else cout << "bad " << obj.testInt << endl;
if(obj1.worked()) {
cout << "1good " << obj1.testInt << endl;
} else
cout << "1bad " << obj1.testInt << endl;
return 0;
}
這是運行時的輸出
bad 99
1good 22
我怎么得到它,所以obj = obj1; (可以在上面的main中找到)使obj.worked()返回true(因為obj1的類是這樣定義的)? 從本質上講,如何使它表現得像Java中那樣? 我不需要深層副本,我只想扔掉obj用來引用的東西,並使其指向obj1(我認為這就是它在Java中的工作方式)。
注意:我對Java不太熟悉。
C ++和Java中的“變量”之間存在主要區別:
class X { public: int m = 5; };
X a; // no `= X();` required
X b;
a = b;
a.m = 42;
print(b.m); // this line is pseudo-code
在Java中,變量可能指向不同的對象。 在上面的示例中,分配后, a
和b
指向同一對象。 通過一個對象修改該對象時,通過另一個對象訪問該對象將使修改可見, print(bm)
將打印42
。
在C ++中,“變量”(實際上是names )始終引用同一對象。 有兩個對象,一個叫a
,一個叫b
,並且賦值不會改變。 按照默認/慣例,C ++中的賦值表示(深層)復制。 a = b
將被大多數人解釋,並且對於內置類型, 將b
的內容復制到a
(或更正式地, 將a
更改a
以后將等於b
,而不更改b
)。
現在應該很清楚,你不能改變它的覆蓋worked
將被稱為使用C ++中的分配:其中一個虛函數基於對象(動態類型)的類型選擇被稱為覆蓋,並且你不能更改名稱(變量)所引用的對象。
但是,C ++中有一些指針,即所謂的原始指針和智能指針 。 指針本身就是指向一種特定類型的其他對象的對象。 X*
是原始指針, 即使具有多態性也指向X
類型的對象! 同樣, std::shared_ptr<X>
是指向類型X
的對象的智能指針。
std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();
每個make_shared
都會創建一個對象。 因此,在此示例中,我們有四個對象: pa
, pb
和兩個通過make_shared
創建的未命名對象。
對於指針,有幾個用於處理所指向對象的運算符。 最重要的是星號,它取消了指針的引用 。 *pa
將為您提供pa
指向的對象。 pa->
運算符是(*pa).
的簡寫(*pa).
,因此您可以使用它來訪問所指向對象的成員。 指針的分配不會復制所指向的對象 。 在分配pa = pb
,兩者將指向同一對象 。 對於智能指針,這意味着清除不再引用的對象:
std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();
// 4 objects exist at this point
pa = pb;
// only 3 objects still exist, the one `pa` formerly pointed to was destroyed
現在,C ++中的多態可與引用(此處未解釋)或指針一起使用。 我之前說過,指針只能指向一種特定類型的對象。 問題的關鍵是該對象可能是更大對象的一部分,例如通過合成。 但是C ++中的繼承與組合非常相似:基類的所有成員都成為派生類對象的基類子對象的一部分:
std::shared_ptr<Obj1> pobj1 = std::make_shared<Obj1>();
std::shared_ptr<Obj> pobj = pobj1;
這里, pobj
指向對象*pobj1
內的Obj
基類子對象(即,對象pobj1
內的對象)。
現在,多態通過虛擬函數起作用。 那些有一個實際調用函數的特殊規則。 *pobj
表達式為我們提供了pobj
指向的對象,它的類型為Obj
。 但是在此示例中,它只是一個基類子對象 ,即我們最初創建的對象是從Obj
派生的類型。 對於這些情況,我們區分表達式的靜態 類型和動態類型 :
*pobj
總是Obj
-通常,對於對象p
,其類型為指針some_type
,靜態類型的*p
只是some_type
,移除/一個指針到一個間接層。 *pobj
的動態類型取決於pobj
當前指向哪個對象,因此在編譯時通常是未知的。 如果對象是基類子對象 ,則使用它所屬的派生類對象 ,然后遞歸直到我們擁有的對象不再是基類子對象 。 我們最終得到的對象的類型是表達式的動態類型。 在上面的示例中, pobj
指向*pobj1
的Obj
基類子對象 。 *pobj1
對象本身不是此處的基類子對象 ,因此*pobj
的動態類型是Obj1
。 現在,此動態類型用於選擇調用哪個虛擬函數替代。 在pobj->worked()
的情況下, *pobj
的動態類型是Obj1
,選擇的替代項是Obj1::worked
,它將返回true。
注意:正如Ben Voigt所指出的那樣,動態類型並不取決於組成。 它僅與繼承有關。
在C ++中,您的對象是值,而不是Java中的引用。 分配(obj = obj1)將引用Obj1的Obj部分。 在C ++中,您必須使用指針或引用。
指針
Obj* obj = new Obj(99); Obj1* obj1 = new Obj1(45); delete obj;// you have to free the memory manually as there's no GC in C++ obj = obj1; obj->Worked();// the worked will be true here delete obj1; // manually delete it
如果要通過obj刪除obj1(刪除obj而不是delete obj1),則必須將Obj的析構函數更改為虛擬,否則將不會調用Obj1的析構函數。 該死的,這是C ++,喜歡它。
參考
Obj obj = Obj(99); Obj1 obj1 = Obj1(45); Obj& obj2 = obj1; obj2.Worked() // should be true
在這種情況下,與指針不同,您不必刪除對象,因為它們在堆棧中(不是由“ new”創建的)。 但是您不能創建Obj&的數組(例如向量)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.