2010-05-21 40 views
0

是的,我知道這句話的「虛擬構造函數」是沒有意義的,但我仍然看到文章這樣正在使用C++「虛擬構造器」通常被認爲是良好的做法?

之一:http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=184

和我心中已經聽到它提到的一個C++的採訪。

什麼是普遍的共識? 是一個「虛擬構造器」的良好實踐還是應該完全避免的事情?

更確切地說,有人可以爲我提供一個真實世界的場景,他們不得不使用它,從這裏我可以體驗到這個概念。構造。是一個有點無用的發明,但我可能是錯的。


+4

看起來像寫得很差的工廠模式。 – kennytm 2010-05-21 19:07:44

+0

看起來像一個Java開發人員正試圖跨越C++而不理解範例。 – 2010-05-21 19:56:13

回答

1

作者所做的全部工作就是實現原型和克隆。這兩者都是模式庫中的強大工具。

實際上,你可以做一些事情很多通過使用手柄/身體成語的接近「虛擬構造函數」:



struct object 
{ 
    void f(); 
    // other NVI functions... 
    object(...?); 
    object(object const&) 
    object& operator = (object const&); 
    ~object(); 

private: 
    struct impl; 
    impl * pimpl; 
}; 

struct object::impl 
{ 
    virtual void f() = 0; 
    virtual impl* clone() = 0; 
    // etc... 
}; 

struct impA : object::impl { ... }; 
struct impB : object::impl { ... }; 

object::object(...?) : pimpl(select_impl(...?)) {} 
object::object(object const& other) : pimpl(other.pimpl->clone()) {} 

// etc... 

不知道是否有人已經宣佈這個成語,但我發現它很有用,我相信其他人自己也會遇到同樣的想法。

編輯: 當您需要請求接口的實現並且不希望將呼叫站點連接到抽象背後的繼承樹時,可以使用工廠方法或類。

您使用原型(clone())來提供抽象的通用複製,以便您不必爲了創建該副本而確定類型。

你會使用像我剛纔給幾個不同的原因:

1)你完全封裝的抽象背後的繼承關係。這是這樣做的一種方法。

2)你希望把它當作在抽象層面的值類型(你會被迫使用指針或其他東西)

3)您最初有一個實現,並希望增加新的不規範必須更改客戶端代碼,這些代碼都使用原始名稱進行自動聲明或按名稱分配堆。

+0

AFAIK,這就是所謂的PIMPL(私人執行),不透明指針,處理習慣用語和可能更多 - 以防萬一任何人希望谷歌更多的信息。 – rholmes 2013-12-04 14:29:20

+0

它擴展了pimpl慣用法以提供值的語義多態性。通常,您列出的成語不會繼承impl。 – 2013-12-04 18:39:25

+0

感謝Eddie的澄清。我在重讀時看到你的觀點。它看起來有點像沒有可選接口層次結構的Bridge(如果目標是封裝繼承關係,這是有道理的)。它對於一些工廠變體看起來也是一個有用的構建塊。好東西。 – rholmes 2013-12-10 03:29:10

0

這是你可以使用的東西,但只有當你真的,真的需要它。即使鏈接中的人說,這只是你絕望時使用的東西。

1

編寫「虛擬構造函數」的最好方法是使用具有Clone()虛擬方法的Prototype模式,該方法調用對象的實際類型的複製構造函數並返回指向基類的指針。


class Base 
{ 
public: 
    virtual Base* Clone() { return new Base(*this); } 
}; 

class Derived : public Base 
{ 
    virtual Base* Clone() { return new Derived(*this); } 
}; 

它不被認爲是很好的做法,只有當你需要它(實現例如複製粘貼功能)

1

我認爲這些所謂的「虛擬構造函數」一糟糕的設計使用而不是構造函數。這些只不過是虛擬函數,應該在類的實例的使用開始時被調用。

從鏈接您發佈:

class Browser 
{ 
public: 
    //virtual default constructor 
    virtual Browser* construct() {return new Browser;} 
}; 

讓我們添加一個成員字段:

class Browser 
{ 
    int member; 
public: 
    //virtual default constructor 
    virtual Browser* construct() {return new Browser;} 
}; 

我們需要初始化成員字段,我們該怎麼做呢?

class Browser 
{ 
    int member; 
public: 
    //virtual default constructor 
    virtual Browser* construct() 
    { 
    Browser* b = new Browser; 
    b->member = 0; 
    return b; 
    } 
}; 

考慮一個情況,當有人忘記使用template <class T> void func(T & obj)和做這樣的事情:

Browser b; 
printf("member=%d", b.member); 

這種方式使用未初始化的領域。沒有辦法阻止它。

現在,在這種情況下

class Browser 
{ 
    int member; 
public: 
    Browser() : member(0) { } 
    virtual Browser* construct() { /* some init stuff */ return new Browser;} 
}; 

默認構造函數總是使用和成員字段總是初始化。 但是,將construct()稱爲「虛擬構造函數」,我認爲這是一種命名濫用。

我上面顯示的模式很常見,例如。在MFC中。 CWnd和類似的類使用構造函數來初始化實例和Create(...)函數來完全初始化和創建控件。無論如何,我永遠不會把Create(...)函數稱爲「虛擬構造函數」。

0

以上所有答案都不回答問題,但提供了一些解決方法。上述問題的答案是直接來自語言作者本身的http://www.stroustrup.com/bs_faq2.html#virtual-ctor。總之它說你需要完整的信息來構造一個對象,因此虛擬構造函數在C++中不存在。

相關問題