2011-11-17 68 views
3

我試圖讓每個類的實例(在這裏命名爲Caller)具有另一個類的實例(Target)。關鍵是第二堂課有很多孩子,我需要能夠隨意在他們之間切換Caller。我嘗試了幾種方法,但沒有一個給我任何理想的結果。當前代碼:將類更改爲子類

class Target 
{ 
public: 
    virtual void do_something() 
    { log_message("NO!"); } 
}; 

class TargetChild : public Target 
{ 
public: 
    virtual void do_something() 
    { log_message("YES!"); } 
}; 

class Caller 
{ 
private: 
    Target target; 

public: 
    void call_target() 
    { target.do_something(); } 
    void set_target(Target set_target) 
    { target = set_target; } 
}; 

int main(int argc, const char* argv[]) 
{ 
    TargetChild targetChild; 

    Caller caller; 
    caller.call_target(); 
    caller.set_target(targetChild); 
    caller.call_target(); 
} 

日誌文件中想要的結果是「NO!YES!」但是它寫了NO!兩次。我真的不知道它有什麼問題。

回答

6

您不能在C++中更改對象的類型。您只能創建,銷燬,複製和(在C++ 11中)移動數據。在這種情況下,您已將數據從子類對象複製到基類對象。這複製了一個空子集的空子集。你觀察到的問題叫做「切片」。

可能你想要的是一個包含可以改變的函數指針的成員。 virtual給你一個函數指針,但它不能被改變。試試std::tr1::functionboost::function或C++ 11 std::function。或者,如果您確實想要使用virtual路由,請使用Target *指針。最好使用智能指針類,例如unique_ptr<Target>(又是Boost/TR1/C++ 11)或std::auto_ptr<Target>(老式的C++ 03)。你也可以用newdelete自己來完成,但是這樣的代碼實際上並不能很好地工作,只適用於一些教育修補。

+0

非常感謝。由於我已經包含它,可能會嘗試Boost方式。 –

+0

使用Boost的智能指針解決。非常感謝! –

0

改爲使用指針。更多關於多態性:http://www.cplusplus.com/doc/tutorial/polymorphism/

... 
class Caller 
{ 
    private: 
     Target* target; 

    public: 
     Caller() { target = NULL; } 
     void call_target() { if (target != NULL) target->do_something(); } 
     void set_target(Target* set_target) { target = set_target; } 
}; 

int main(int argc, const char* argv[]) 
{ 
    .... 
    caller.set_target(&targetChild); 
    ... 
} 
+0

垃圾,我忍住了。 :)) – Tudor

+0

您正在調用未定義的行爲,因爲第一次調用'call_target'發生在單位化指針上(假設您將其餘代碼保留在'main'中)。 –

+0

將指針檢查添加到'call_target'中... –

0

在set_target你是按值傳遞targetChild,有你正在失去致電TargetChild :: do_something的機會。您需要擴展調用方以包含對當前目標的引用(或指針),引用(或指針)將保留有關原始TargetChild的信息,然後編譯器仍將調用TargetChild :: do_something。

1

您的代碼患有object slicing。儘管main中的targetChildTargetChild,但它的值被傳遞到Caller::set_target,這意味着它被複制到類型爲Target的局部變量。一般來說,要繞過對象切片,必須使用傳遞引用或使用指針。

在這種情況下,由於您希望Caller訪問Caller::set_target方法之外的傳遞對象,因此應該使用指針。單獨的參考將不起作用,因爲儘管您可以將Caller::target作爲參考,但您無法更改其引用的對象。

指針引入了內存管理問題,因爲您必須確保TargetChild被釋放(否則程序有內存泄漏),但不會太早(這會導致訪問衝突,很可能會導致程序崩潰)。助推庫有各種類型的smart pointer類,以使這更容易。如果在任何時間點只有一個其他類應擁有TargetChild實例,則也可以使用C++標準auto_ptr類。

+0

感謝您提供的鏈接,它們也非常有幫助。 –

0

使用接口,ITarget和隨意切換 他們ITarget

virtual void do_something()  { log_message("NO!"); } 

對待一切,ITarget

類型的處理它這是一個巧妙的方法。

我的C++很生鏽:)