1

我目前正在編寫一個複雜的類,並在其中我基本上需要複製派生類的列表。簡化版本,如下所示: 我有一個基類從中我獲得其他的幾類:C++賦值運算符=用派生類重載

class Base 
{ 
public: 
    virtual void test(void) 
    { 
     cout << "Base" << endl; 
    } 
    Base(vector<Base*> *pointer) 
    { 
     pointer->push_back(this); 
    } 
    virtual Base& operator=(const Base& rhs) 
    { 
     cout << "Base=" << endl; 
     return *this; 
    } 
}; 
class A : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "A" << endl; 
    } 
    A(vector<Base*> *pointer) : Base(pointer) {} 
    A& operator=(const A& rhs) 
    { 
     cout << "A=" << endl; 
     return *this; 
    } 
}; 
class B : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "B" << endl; 
    } 
    B(vector<Base*> *pointer) : Base(pointer) {} 
    B& operator=(const B& rhs) 
    { 
     cout << "B=" << endl; 
     return *this; 
    } 
}; 

然後我創建對象,這是我在保存在Base類的指針列表的列表:

這些對象,然後我想在同一個班(順序相同)第二列表複製,但它可能有不同的值。

for (int i = 0; i < (int)listA.size(); i++) 
{ 
    (*listA[i]) = (*listB[i]); 
} 

但是C++無法做到這一點。由於列表的類型是Base *,因此dereferencing會創建一個Base類型的對象。因此調用基類的賦值運算符=而不是從派生類中正確的。我怎樣才能解決這個問題?

或者我該如何告訴C++使用正確的運算符?也許由一些isinstanceof功能?

對於全樣本見:

int main() 
{ 
    vector<Base*> listA; 

    new Base(&listA); 
    new A(&listA); 
    new B(&listA); 

    vector<Base*> listB; 

    new Base(&listB); 
    new A(&listB); 
    new B(&listB); 


    for (int i = 0; i < (int)listA.size(); i++) 
    { 
     (*listA[i]).test(); 
    } 
    for (int i = 0; i < (int)listA.size(); i++) 
    { 
     (*listA[i]) = (*listB[i]); 
    } 
} 

,輸出:

Base 
A 
B 
Base= 
Base= 
Base= 
+0

可能的重複[爲什麼派生類不使用基類操作符=(賦值操作符)?](http://stackoverflow.com/questions/10838211/why-doesnt-a-derived-class-use -base-class-operator-assignment-operator?rq = 1) –

+0

將'A'分配給'B'或反之亦然是什麼意思? – aschepler

回答

0

好的。我爲我的問題找到了解決方案。我實現了一個以Base類爲參數的複製函數。在這個複製功能裏,我可以使用pointa複製變量。該CLASSE現在如下:

class Base 
{ 
public: 
    virtual void test(void) 
    { 
     cout << "Base" << endl; 
    } 
    Base(vector<Base*> *pointer) 
    { 
     pointer->push_back(this); 
    } 
    virtual void clone(Base* pointer) = 0; 
}; 
class A : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "A" << endl; 
    } 
    A(vector<Base*> *pointer) : Base(pointer) {} 
    void clone(Base* pointer) override 
    { 
     A* pointa = (A*)pointer; 
     cout << "clone A" << endl; 
     //Clone Variables here 
    } 
}; 
class B : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "B" << endl; 
    } 
    B(vector<Base*> *pointer) : Base(pointer) {} 
    void clone(Base* pointer) override 
    { 
     B* pointa = (B*)pointer; 
     cout << "clone B" << endl; 
     //Clone Variables here 
    } 
}; 

這意味着我現在就可以通過以下方式複製這些對象:

for (int i = 0; i < (int)listA.size(); i++) 
{ 
    listA[i]->clone(listB[i]); 
} 

但是這種解決方案是不以任何方式類型安全,我想,以滿足需求。我研究了我的想法,並決定不用列表手動完成任務,這意味着很多重複的代碼,但會帶來安心。

2

這裏有一些誤解。首先,最重要的是,將派生類的實例分配給基類的實例意味着什麼?讓我們舉一個簡單的層次結構:

struct A { int x; }; 
struct B : A { int y; }; 

A a; 
B b; 
a = b; // what should this do? 
b = a; // what about this? 

與普通C++,第一個做object slicing,並形成不良的第二個。但即使是第一個,結構良好,通常也不是你想要做的。你是肯定你想要切片嗎?


第二個是,當你做你的賦值運算符的虛擬:

virtual Base& operator=(const Base& rhs) 

派生類中沒有真正覆蓋它。 A的賦值操作符需要A const&B的需要B const&。如果你用override標記了兩個,你的編譯器會給你指出。如果你解決了這兩個問題以採取一個Base const&的論點,那麼你會得到你想要的東西 - 但它可能仍然不是你想要發生的事情。


爲了真正使多態副本,一個典型的解決方案是提供一個虛擬的克隆方法:

virtual Base* clone() const = 0; 

那你的派生類實現:

struct A : Base { 
    A* clone() const override { return new A(*this); } 
}; 

然後用clone()而不是分配。這裏沒有切片。


在這裏插入關於內存管理和原始指針的通常注意事項。

+0

謝謝!我明白你在說什麼。只有最後一部分我不能包裹我的頭。我如何在實踐中使用這個克隆功能? – jansende

+0

你的意思是完全取代舊物件?不幸的是,這不是一個選項! – jansende