2016-08-30 105 views
7

說我有一個類:是否可以在同一個類中創建一個類的實例?

class Foo{ 
public: 

    Foo(){ 
    } 

    //Is it possible to create a function like this: 
    virtual Foo* createOb(){ 
     //Should create a new Foo,Bar or Fiz, depending on the actual object type. 
    } 
} 

class Bar: public Foo{ 
public: 

    Bar(){ 
    } 
} 

class Fiz: public Foo{ 
public: 

    Fiz(){ 
    } 
} 

是否有可能有一個方法createOb()在基類的,所以當createOb()被調用所導出的類之一的實例,其的一個實例派生類是否被創建?

+0

如果您在不同的cpp文件我想這應該有可能分裂它。你是否正在尋找基類的克隆函數而不知道它是什麼子類?你可以看看這種方法:https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/ – Hayt

+0

@ c.bear但是Foo不知道派生類......我是C++的新手,所以我不知道你的意思...... –

回答

5

是的目的,這是可以做到,使用CRTP

首先,返回從new獲得的原始指針是非常危險。在c++中,只有當原始指針不具有指向對象的所有權時,才應使用原始指針。所以我冒昧地使用unique_ptr

struct Base { 
    virtual auto create_obj() -> std::unique_ptr<Base> 
    { 
    return std::unique_ptr<Base>{}; 
    } 
}; 

// abstract works too: 
struct Base { 
    virtual auto create_obj() -> std::unique_ptr<Base> = 0; 
}; 

template <class Derived> 
struct Base_crtp : Base { 
    auto create_obj() -> std::unique_ptr<Base> override /* final */ 
    { 
    return std::unique_ptr<Base>{new Derived{}}; 
    } 
}; 

struct D1 : Base_crtp<D1> 
{ 
}; 

struct D2 : Base_crtp<D2> 
{ 
}; 

然後:

auto b1 = std::unique_ptr<Base>{new D1{}}; 
auto b2 = std::unique_ptr<Base>{new D2{}}; 

auto new_d1 = b1->create_obj(); 
auto new_d2 = b2->create_obj(); 
+0

可能不是每個人都會得到的東西是如何採用它來複制構造函數(在'create_obj'中將'this' ptr轉換爲'Derrived'。不知道在別人使用此解決方案的情況下是否可以幫助添加它所以這將是'返回std :: unique_ptr {新的派生{static_cast (* this)}};'如果需要的話 – Hayt

+0

@Hayt'克隆'在維基頁面中有例子我鏈接 – bolov

+0

阿好了。沒有看到那是一個鏈接:) – Hayt

0

不,這是不可能的「純」繼承。這些類必須重寫createOb()成員函數才能支持克隆。

你可以看到爲什麼這是不可能的考慮分開編譯類。一竅不通的createOb()成員函數的實現必須與BarFiz分開完成,這使得基類不可能知道其子類的類型。但是,在基礎中使用純虛函數的實現非常普遍。

另一種方法是使用好奇地循環模板模式(CRTP)來實現克隆。這article解釋瞭如何完成。

+0

根據情況,基於CRTP的方法也很常見。但是看到約翰是C++的新手,這可能會讓初學者感到困惑。 – Hayt

+0

@Hayt我已經在使用類似CRTP的東西了,但是對於我來說我的頭很難纏。我更喜歡簡單的東西,即使它是黑客,只要它正常工作。 –

+0

聽起來就像我將不得不更新所有派生類! :(太多了...... –

0

這不是一個最佳的解決方案,但它的工作原理。

在您的.h

class Foo{ 
public: 
    Foo(); 
    virtual Foo* createOb(); 
}; 

class Bar: public Foo{ 
public: 
    Bar(); 
}; 

class Fiz: public Foo{ 
public: 
    Fiz(); 
}; 

在你的.cpp

#include "Header.h" 

Foo::Foo() {} 

Foo* Foo::createOb(){ 
    if (dynamic_cast<Bar*>(this)) { 
     return new Bar(); 
    } 
    else if (dynamic_cast<Foo*>(this)) { 
     return new Foo(); 
    } 
    return nullptr; 
} 

Bar::Bar() {} 
Fiz::Fiz() {} 

正如已經建議請考慮一個純虛方法

+0

似乎約翰有很多「興旺的班級,雖然 – Hayt

+0

問題是,Foo將不得不知道酒吧,Fiz等的存在...我要去嘗試黑客一起宏... XD –

+0

海耶是正確....我有很多派生類,並將繼續添加更多! –

1

肯定是有的!

當一個方法在基類中聲明爲虛擬並通過派生類對象調用時,派生類函數被調用(在vC++中讀取vprt,vtable概念)。

#include <iostream> 

using namespace std; 

class A{ 
     public: 
     virtual A* getobj(){ 
     return new A(); 
     } 
}; 
class B: public A{ 
     public: 
     B(){cout<<"B constructor"<<endl;} 
     virtual A* getobj(){ 
     return new B(); 
     } 
}; 

int main() 
{ 

A *a = new B(); 
A *second = a->getobj(); 
return 0; 
} 

在上面的代碼中,我們使用類B的對象調用getobj()函數。 這裏B類的構造函數被調用兩次。

  1. 第一,新的B()在主

  2. 其次用於getobj函數調用,它再次產生乙

+0

我認爲ideea是不在每個派生類中編寫相同的代碼。只需在基類中擁有'getobj'的代碼 – bolov

+0

這兩個函數都應該在類 –

+2

中這裏的問題是John有很多類。所以你需要添加這100個以上的課程。這是他想要避免的。 – Hayt

相關問題