2011-12-21 79 views
2

我有兩個不同的類(第一,第二),它繼承了相同的基類(Base)。我想在同一個向量中存儲First和Second的實例,而不將它們的類拼接到Base類。如果我使用向量,會發生這種拼接,就像下面:在同一個向量中存儲兩個不同的類(具有相同的繼承基類)? (沒有提升)

#include <iostream> 
#include <vector> 

class Base { 
    public: 
    Base() { } 
    virtual void test() { std::cout << "I am just the base class\n"; } 
}; 

class First : public Base { 
    public: 
    First() { } 
    void test() { std::cout << "This is the First class\n"; } 
}; 

class Second : public Base { 
    public: 
    Second() { } 
    void test() { std::cout << "This is the Second class\n"; } 
}; 

int main() { 
    First *f = new First(); 
    Second *s = new Second(); 

    // First, I keep a vector of pointers to their base class 
    std::vector<Base> objs; 
    objs.push_back(*f); 
    objs.push_back(*s); 
    objs[0].test(); // outputs "I am just the base class" 
    objs[1].test(); // outputs "I am just the base class" 
} 

最終,當兩個物體放入到載體,它們拼接。有沒有辦法(沒有提升)複製這兩個對象到同一個向量?一個向量不是我正在尋找的,我想複製這些對象。


這裏有很多很好的答案。不幸的是,我不能假定C++ 11,所以我最終利用克隆構造函數提示存儲指針。但最終,克隆允許我首先創建副本。

這是我最後的解決辦法:

#include <iostream> 
#include <vector> 

class Base { 
    public: 
    Base() { } 
    virtual void test() { std::cout << "I am just the base class\n"; } 
    virtual Base* clone() const = 0; 
}; 

class First : public Base { 
    public: 
    First() { } 
    void test() { std::cout << "This is the First class\n"; } 
    First* clone() const { return new First(*this); } 
}; 

class Second : public Base { 
    public: 
    Second() { } 
    void test() { std::cout << "This is the Second class\n"; } 
    Second* clone() const { return new Second(*this); } 
}; 

int main() { 
    First *f = new First(); 
    Second *s = new Second(); 

    std::vector<Base *> bak; 
    bak.push_back(f->clone()); 

    bak[0]->test(); 

} 
+2

我認爲你的意思是'切片'。 「拼接」恰恰相反。 – 2011-12-21 07:35:17

+1

只要確保在使用沒有智能指針的克隆()時,刪除您克隆的所有內容 – stefaanv 2011-12-21 15:24:33

回答

3

要複製不分片的繼承對象,需要在基類中定義clone()函數並在派生類中重寫:

class Base 
{ 
public: 
    Base* clone() const = 0; 
} 

class Derived 
{ 
    Derived* clone() const { return new Derived(*this); } 
} 

這樣,即使有指向基類的指針,您也會得到派生類的副本。

2

是的,您可以創建指針的vectorBase

std::vector<Base*> objs; 

,或者更好的是,智能指針到基類的vector,所以你不需要擔心內存管理。

+0

我正在尋找複製對象,抱歉不澄清。 – gnychis 2011-12-21 07:31:19

+0

@gnychis我不明白。如果你想複製對象,有一個複製構造函數... – 2011-12-21 07:32:42

+0

@gnychis:然後深拷貝指針。否則,它不能做 – 2011-12-21 07:33:04

1

redifine副本constractor,然後使用:

std::vector<Base*> objs; 
objs.push_back(new First(*f)); 
objs.push_back(new Second(*s)); 
2

我不知道爲什麼你要複製的對象,但如果它是很容易的內存管理,那麼這將做到:

std::vector<std::shared_ptr<Base> > objs; 
objs.push_back(std::make_shared<First>()); 
objs.push_back(std::make_shared<Second>()); 
+0

注:標準:: make_shared是C++ 11和C++中不可用03 – mark 2011-12-21 09:42:27

+0

@馬克:'的std :: shared_ptr'也沒有在C++ 03提供。關鍵是OP可以用智能指針解決他的問題。智能指針的命名空間是不相關的。他也可以使用'boost ::'。 – 2011-12-21 09:55:59

+0

@sad_man:OP以「(無提升)」命名爲其帖子。 不,在C++ 03中沒有std :: shared_ptr(除了一些實驗性的extesions:shared_ptr已被批准爲C++ 11中的「標準」,本質上是通過使用C++ 11特定功能重寫boost :: shared_ptr ) – 2011-12-21 20:22:19

1

通過您制定問題的方式,是不可能辦到的事: vetor<Base>持有Base個序列,而FirstSecond都是Base加上更多的東西。

由於它的本質,矢量包含相同對象(所有Base)和push_back的序列,實際上並不將對象放置在矢量中,而是將對象複製到矢量結尾構建的對象(並且是Base對象,因此只有Base子組件被複制)。

要解決這個問題,你必須讓你的矢量不要「包含」Base -s,而是要「引用」Base-s。這需要指針

std::vector<Base*> v; 
v.push_back(new First); 
v.push_back(new Second); 

但這也需要內存管理。這可以通過兩種方式完成:

1)使用「擁有」基地的一些智能指針。 在C++ 11中有std::shared_ptrstd::unique_ptr。 在C++ 03,你必須安排自己的引用計數指針像

template<class T> 
class ptr 
{ 
public: 
    ptr() :p(), c() {} 
    explicit ptr(T* z) :p(z), c(new unsigned(1)) {} 
    ptr(const ptr& s) :p(s.p), c(s.c) { if(c) ++*c; } 
    ptr& operator=(const ptr& s) 
    { 
    if(this!=&s) 
    { 
     if(c && !--*c) { delete p; delete c; } 
     p = s.p; c=s.c; 
     if(c) ++*c; 
    } 
    return *this; 
    } 
    ~ptr() { if(c && !--*c) { delete p; delete c; } } 

    T* operator->() const { return p; } 
    T& operator*() const { return *p; } 

private: 
    T* p; 
    unsigned* c; 
}; 

,並宣佈爲

std::vector<ptr<Base> > v; 
v.push_back(ptr(new First)); 
v.push_back(ptr(new Second)); 
v[0]->test(); 
v[1]->test(); 

銷燬v您的載體,將會破壞又會破壞對象的師生比。 注:基地還必須聲明一個虛析構函數,否則派生的對象不能被plymorphically破壞。

2) 或者,你可以在「自定義」矢量「擁有」指針本身。 這可以通過類似

template<class T> 
class owningvector: public std::vector<T*> 
{ 
public: 
    ~owningvector() 
    { 
    for(size_t i=0; i<size(); ++i) 
     delete at(i); 
    } 
    owningvector() {} 
private: 
    //disable vector copy and assign 
    owningvector(const owningvector&); 
    owningvector& operator=(const owningvector&); 
}; 

owningvector<Base> ov; 
ov.push_back(new First); 
ov.push_back(new Second); 

注意索取:Base仍然需要虛析構函數。 另外,由於std::vectorownvector對於銷燬沒有多態性,所以不要將自己用作多態類型。

3) 如果你是on_stack做的一切,你可以很容易做到

int main() 
{ 
    First first; 
    Second second; 
    std::vector<Base*> v; 
    v.push_back(&first); 
    v.push_back(&second); 

    v[0]->test(); 
    v[1]->test(); 

    //no other memory management is required: 
    // v is destroyed without doing anything special. 
    // second and first are destroyed just further. 
} 
1

,我被你說,你要複製你的對象intreged。 通常,多態性和複製/分配不能很好地協同工作, 但您可以通過使用letter-envelop慣用語來實現。喜歡的東西:

class Base 
{ 
    Base* myImpl; 
    virtual Base* clone() const 
    { 
     // or perhaps just abort, since this one shouldn't 
     // ever be called in practice. 
     return new Base(myImpl->clone()); 
    } 
protected: 
    Base() : myImpl(NULL) {} 
    Base(Base* impl) : myImpl(impl) {} 

public: 
    Base(Base const& other) : myImpl(other.myImpl->clone()) {} 
    virtual ~Base() {} 
    virtual void test() { myImpl->test(); } 
}; 

class First : public Base 
{ 
    virtual Base* clone() const 
    { 
     return new First(*this); 
    } 

    First() {} 
public: 
    static Base createInstance() { return Base(new First); } 
    virtual void test() { std::cout << "In First" << std::endl; } 
}; 

class Second : public Base 
{ 
    virtual Base* clone() const 
    { 
     return new Second(*this); 
    } 

    Second() {} 
public: 
    static Base createInstance() { return Base(new Second); } 
    virtual void test() { std::cout << "In Second" << std::endl; } 
}; 

這導致的一類Base其行爲多態,但 支持複製和賦值(和分配可以改變有效 型),並不會切片。這也導致了嚴重的性能命中, 通常不是什麼都想在我的經驗反正—,最 多態類是有身份的,而不應該是可複製或 分配。但這是一個可能的解決方案,並且在某些特定情況下可能會有用。

相關問題