2011-10-04 58 views
1

我有一些設計問題,我想你們中的一個可能有一些線索來幫助我。使用boost :: shared_ptr的set中的不同模板類class =「#」#:

我想總結一下我的問題這個簡單的例子:

我有兩個不同的類DerivedOneDerivedTwo從同一Base類繼承和共享方法的定義。
我有一套shared_ptr指向client,其中有一個對象來自兩個不同的類DerivedOneDerivedTwo
因爲我不想用Base*指針來保存這2個不同的類,所以我嘗試製作客戶端類模板。

但是我有兩個不同的班級,我不能在同一組中持有他們。
我認爲shared_ptr可以容納一個對象指針而不指定模板參數,但我錯了,或者我不知道該怎麼做。

另一種解決方案我看到的,是預先分離的那些2個不同client在2個不同的set

感謝您的任何建議。

下面是代碼:

#include <iostream> 
#include <set> 
#include <boost/shared_ptr.hpp> 

class Base 
{ 
    public: 
     virtual void test() = 0; 
}; 

class Derived_one 
    : public Base 
{ 
    public: 
     void test() { 
      std::cout << "Derived One" << std::endl; 
     }    
}; 

class Derived_two 
    : public Base 
{ 
    public: 
     void test() { 
      std::cout << "Derived Two" << std::endl; 
     } 
}; 

template <class temp_arg> 
class Client 
{ 
    public:   
     int test(){ 
      obj_.test(); 
     } 

    protected: 
     temp_arg obj_; 

}; 

typedef Client<Derived_one> ClientOne; 
typedef Client<Derived_two> ClientTwo;  

/// Here I don't want to specify any of the two previously declared client : 
//typedef boost::shared_ptr<Client> Client_ptr; 
typedef boost::shared_ptr<ClientOne> Client_ptr; 

int main(int, const char**) 
{ 
    std::set<Client_ptr> Clients_; 
    Client_ptr client_(new ClientOne()); 

    Clients_.insert(client_); 
    client_->test(); 

    return 0; 
} 

如果你想給看向真正的代碼:
https://github.com/gravitezero/Node/tree/experimental/src
Client對應connection
Base類是message
兩個派生類是peplyrequest

+0

爲什麼你不想使用Base指針,它可能指向派生類對象? –

+0

由於某些原因,我不想使用指針。 其中之一是我不想'dynamic_cast',並且這個指針可能會變成'dynamic_cast'。 此外,我想要一個組合,而不是客戶端和派生對象之間的聚合。 – etnbrd

+0

@EtienneBrodu如果你需要一個'dynamic_cast',你的設計在另一個地方出了問題,但是在你給我們展示的那個地方沒有。指針是一個非常合理的決定。 – pmr

回答

0

boost共享模板指針不會執行任何你沒有常規指針(即將兩個不同類型放入同一個集合中)無法實現的魔法。無論何時使用模板,您都必須顯式聲明模板參數,因爲模板中的所有內容都會在編譯時爲您生成重複的代碼。因此,當您使用模板時,編譯器只需複製模板文件多次,就像您使用模板參數聲明的那樣。沒有模板參數,沒有重複,沒有模板。至少這是我的理解,我相信如果我錯了,C++警察會糾正我。

因此,將兩種不同類型放入同一個集合的方法是屏蔽集合中的值。這樣做的最基本的方法(和壞的方法)是使你的收集的空指針,然後根據上下文進行插入和提取。這是很危險的,因爲那樣你將通過指針訪問內存,而不檢查指針是否指向正確的內存量(這是類型檢查)。

所以真正的做法是按照pmr的建議。使您的集合成爲基本類型指針的集合,並在插入和從列表中提取時使用動態強制類型轉換類型。動態投射會在運行時檢查以確保您正在投射的類型與兼容。 IE如果你從Derived1轉換到Base,然後再從Base轉換到Derived1,這沒問題。如果您從Derived1轉換爲base,然後再從base轉換爲Derived2,則指向同一內存的指針將在運行時失敗,因爲Derived2和Derived1不兼容。

這個解釋有點長,因爲幾個月前我有同樣的設計問題,直到我做了一些閱讀。

0

爲什麼不想使用指向Base實例的指針?如果你使用運行時多態,這是唯一的方法。如果你實際上不需要運行時多態,虛擬成員函數是錯誤的方法。

只需使用boost::scoped_ptr或(更好)C++ 11 std::unique_ptrbase*保留爲Client

如果您選擇放棄運行時多態,您應該查看CRTP以實現靜態多態。

+0

實際上,這兩個派生類的一些成員是常見的,所以我使用了這個Base類,並且我也使這個方法是虛擬的,但它並不是真的需要。我多次改變了這個設計,我沒有想到它不再需要。 我不想要runtime-polymorphisme,因爲我想我可以在編譯時處理這個問題。但我可能會絞痛。 我從來沒有聽說過CRTP,我要去獲得一些文檔,謝謝:) – etnbrd

+0

@EtienneBroduct,CRTP不會幫忙,因爲它依賴於不同的模板實例,你已經發現它是一個問題。但是,無論如何這裏有一個介紹:http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

+0

@MarkRansom但他會得到一個類似於層次結構的接口,並且可以簡單地保留成員的值,並將Client作爲模板。就我所見,這將解決問題,特別是因爲他指出,運行時操作不是必需的。 – pmr

相關問題