2015-11-03 39 views
1

我一直在嘗試重寫我的程序以允許繼承類。我遇到了切片問題。我原本在我的Test類中有Parent m_parent(因此在Test中沒有動態分配),但補充說,認爲它會解決我的問題,但它沒有。我不知道我是否會讓我的問題變得更糟,或者如果寫作複製構造函數(或其他簡單修復)那麼簡單。在方法調用中避免對象切片

class Parent 
{ 
    public: 
     Parent(); 
    private: 
     string a; 
}; 
class Child : public Parent 
{ 
    private: 
     string b; 
}; 
class Test 
{ 
    public: 
     Test() 
     { 
      m_parent = new Parent; 
     } 
     void testFunction(Parent &parent) 
     { 
      *m_parent = parent; 
     } 
     ~Test() 
     { 
      delete m_parent; 
     } 
    private: 
     Parent * m_parent; 
}; 

做這樣的事情還是引起了切片...

Child c("foo", "bar"); 
Parent * p = &c; 
Test.testFunction(*p); 
+0

所以要複製母公司的任意派生的實例? – Shaggi

+0

提醒我一個[老問題](http://stackoverflow.com/questions/23220589/code-selector-using-inheritage-during-runtime)我有。自從我使用智能指針。使用[C++ 11](http://www.codeproject.com/Articles/541067/Cplusplus-Smart-Pointers)或[boost](http://www.codeproject.com/Articles/8394/Smart-Pointers -to-升壓你的代碼)。 – William

回答

2

是。這條線:

*m_parent = parent; 

使對象上它到底是什麼被切成Parent對象不分。

除此之外,在你的例子中有很多錯誤代碼行,但我猜它只是因爲它是一個非常具體的問題。

編輯: 有人建議如何避免切片:

template <class T> 
void testFunction(T& t){ 
    static_assert(std::is_base_of<Parent,T>::value,"only subclasses of Parent may be passed to testFunction"); 
    delete m_parent; 
    m_parent = new T(t); //or: new T(std::move(t)); 
} 

編輯2: 如果你傳遞一個子對象的真實對象,而不是作爲一個父親指針本應工作, AKA testFunction(myChild)

EDIT3: @ Jarod42關於clone方法有一個好的觀點。這兩種解決方案可以一起使用

+0

我該如何避免這種情況?我有多個派生對象,我需要爲其中傳遞父對象的方法(這是一個示例)工作。 –

+0

你能否詳細說明其他容易出錯的行?只是好奇... – i4h

+2

@ i4h除了代碼甚至沒有編譯的事實,因爲構造函數沒有主體,Child構造函數不接受參數,並且'Test.testfunction'不是靜態方法,其中一個大問題在於'Test'的實現正在泄漏內存,因爲調用'testFunction'將失去構造函數創建的'm_parent'。之後,'Test'析構函數將嘗試清理不允許觸及或更糟的內存,因爲'm_parent'引用了堆棧中可能已被該點破壞的對象。 – CompuChip

2

沒有對象切片,但m_parent不會成爲Child而只有string a被複制。

如果你想保留一份副本在Test,我建議使用Clone

class Parent 
{ 
public: 
    virtual ~Parent() = default; 
    virtual Parent* Clone() const { return new Parent(*this); } 
private: 
    string a; 
}; 

class Child : public Parent 
{ 
public: 
    Child* Clone() const override { return new Child(*this); } 
private: 
    string b; 
}; 

class Test 
{ 
public: 
    void testFunction(const Parent &parent) 
    { 
     m_parent.reset(parent.Clone()); 
    } 

private: 
    std::unique_ptr<Parent> m_parent; 
}; 
+0

優秀的解決方案:這是最好的解決方案!但是我想知道「沒有對象切片」:我認爲在OP的代碼中,由於引用可能指向一個孩子,所以'* m_parent = parent;'有一個潛在的切片問題。在OP的例子中,雖然使用一個取消引用的父指針來調用該函數來進行引用,但我不確定切片是否在調用之前或賦值之前已經發生... – Christophe

+0

@Christophe:我不會說'* m_parent = parent'是對象切片,它使用'Parent :: operator =(const Parent&)'拷貝'Parent'部分。 – Jarod42