2012-04-17 69 views
1
#include <iostream> 

class aa 
{ 
public: 
    aa(){} 

    aa(aa& obj) 
    { 
     aa1 = obj.aa1; 
    } 

    virtual aa operator =(aa& obj) 
    { 
     aa1 = obj.aa1; 
     return (*this); 
    } 

    virtual aa operator +(aa& obj) 
    { 
     aa1 += obj.aa1; 
     return (*this); 
    } 

    int aa1; 
}; 

class bb: public aa 
{ 
public: 
    bb():aa(){} 

    bb(bb& obj) 
    { 
     bb1 = obj.bb1; 
    } 

    aa operator =(aa& obj) 
    { 
     aa::operator =(obj); 
     bb b1 = dynamic_cast<bb&>(obj); 
     bb1 = b1.bb1;  
     return (*this); 
    } 

    aa operator +(aa& obj) 
    { 
     aa::operator +(obj); 
     bb b1 = dynamic_cast<bb&>(obj); 
     bb1 += b1.bb1; 
     return (*this); 
    } 

    int bb1; 
}; 


int main() 
{ 
    bb b1; 
    bb b2; 

    b1.bb1 = 1; 
    b1.aa1 = 1; 

    b2.bb1 = 2; 
    b2.aa1 = 2; 

    aa &a1 = b1; 
    aa &a2 = b2; 

    a1 = a2; 
    b1 = dynamic_cast<bb&>(a1); 
    b2 = dynamic_cast<bb&>(a2); 

    std::cout<<b1.aa1<<";"<<b1.bb1; 

    bb b3; 
    b3.bb1 = 3; 
    b3.aa1 = 3; 

    aa &a3 = b3; 

    aa &a4 = a2 + a3; 
    b3 = dynamic_cast<bb&>(a4); 

    return 0; 
} 

輸出: 2;2,然後將它在線路b3 = dynamic_cast<bb&>(a4);崩潰給誤差std::bad_cast at memory location 0x0012fdbc..C++重載虛擬+運算

我發現其原因被A2 + A3的表達的結果來作爲類型的對象aa,並且在下一個語句中,我們試圖將其轉換爲無效的派生類型對象,從而導致異常。所以我的問題是我們能否達到上述目的,即aa &a4 = a2 + a3;以上功能有所變化?

+2

你並不需要運營商=虛擬。 operator =返回引用而不是值。總的來說,任務是什麼? – Jagannath 2012-04-17 06:23:37

回答

3

C++有一個調度(基於虛函數)。多態二元運算符不可避免地陷入「雙調度」的情況,因此不能通過簡單的虛函數來實現多態。

此外,由於您正在返回一個值,因此每個子類信息都會丟失。

處理這種情況的更合適的方法是定義一個非多態句柄,該句柄實現操作並保存多態類型,並將委託給它們的操作執行。

class handle 
{ 
public: 
    class aa; 
    class bb; 

    class root 
    { 
    public: 
     virtual ~root() {}   //< required being this polymorphic 
     virtual root* clone()=0; 

     virtual handle add_invoke(const root& r) const=0; //resolve the 2nd argument 
     virtual handle add(const aa& a) const=0; //resolve the 1st argument 
     virtual handle add(const bb& a) const=0; //resolve the 1st argument 
    }; 

    class aa: public root 
    { 
    public: 
     aa(...) { /*set vith a value */ } 
     aa(const aa& a) { /* copy */ } 
     virtual root* clone() { return new aa(*this); } 

     virtual handle add_invoke(const root& r) const 
     { return r.add(*this); } //will call add(const aa&); 

     virtual handle add(const aa& a) const 
     { return handle(new aa(.../*new value for aa with (aa,aa)*/)); } 
     virtual handle add(const bb& a) const 
     { return handle(new bb(.../*new value for bb with(aa,bb)*/)); } 
    }; 

    class bb: public root 
    { 
    public: 
     bb(...) { /*set vith a value */ } 
     bb(const bb& b) { /* copy */ } 
     virtual root* clone() { return new bb(*this); } 

     virtual handle add_invoke(const root& r) const 
     { return r.add(*this); } //will call add(const bb&); 

     virtual handle add(const aa& a) const 
     { return handle(new bb(.../*new value for aa with (bb,aa)*/)); } 
     virtual handle add(const bb& a) const 
     { return handle(new bb(.../*new value for bb with (bb,bb)*/)); } 
    }; 

    handle() :ps() {} 
    //support both copy (by clone) and move (by stole) 
    handle(const handle& s) :ps(s.ps? s.ps->clone(): nullptr) {} 
    handle(handle&& s) :ps(s.ps) { s.ps=nullptr; }; 
    //assign by value, to force temporary assign 
    handle& operator=(handle h) { delete ps; ps=h.ps; h.ps=0; return *this; } 
    //cleanup 
    ~handle() { delete ps; } 

    //the operator+ 
    friend handle operator+(const handle& a, const handle& b) 
    { 
     return (b.ps && a.ps)? b.ps->add_invoke(*a.ps): handle(); 
     //Note: manage also the a+b with one of `a` or `b` as null, if it make sense 
    } 

private: 
    handle(root* p) :ps(p) {} 

    root* ps; 
}; 
+0

現在工作。非常感謝。 – 2012-04-19 04:49:22

0

您正在傳遞一個基類,爲什麼它會將其轉換爲派生類型?您應該捕獲投射的異常,因爲這就是您知道該類型不符合您的預期的方式。

請注意,雖然a1a2是參考bb的情況下,a4不是。這就是爲什麼前兩個演員沒有拋出異常。

2

在派生類中字面重載aa operator +(aa& obj)沒什麼意義。

即使當虛擬現在你會打電話給在任何時間返回aa的方法,所以a2 + a3的結果將是一個aa對象,從來沒有一個BB的對象。它被構造爲bb對象,但被複制到生成的aa對象中,並且副本丟失bb信息。

你應該做的是屏蔽特定版本bb operator +(const bb& obj),注意,然而,這將隱藏原始operator+aa論據,你仍然有the using statement重新定義它或進口。

現在,這些更好的語義,但它不會解決您的問題,因爲在你的情況下,它仍然會調用返回aa對象的operator+。在這種情況下,如果你真的想要解決這個問題,你應該在之前添加a2a3

但實際上,如果您在具有虛擬化功能的父子系統中執行此類操作,您可能會重新考慮您的設計。通常,在任何情況下使用dynamic_cast都應該引起一些眉毛。它當然有它的用途,但是應該儘可能地避免下調。