簡體   English   中英

多態類中的重載賦值運算符

[英]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中,變量可能指向不同的對象。 在上面的示例中,分配后, ab指向同一對象。 通過一個對象修改該對象時,通過另一個對象訪問該對象將使修改可見, 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都會創建一個對象。 因此,在此示例中,我們有四個對象: papb和兩個通過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指向*pobj1Obj基類子對象 *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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM