2013-08-01 94 views
6

大概不是。這裏是我的使用情況:指針是否可以指向const空類或非const類?

我有兩個類A & B.

class A 
{ 
    B *b_; 
};   

class B 
{ 
public: 
    B(): b_string_("") {}; 

private:  
    std::string b_string_; 
}; 

我想B_總是指向一個B對象。我希望b_指向一個「空白」B對象而不是nullptr,這樣我總是可以以定義的方式對* b_進行取消引用來獲得一個空b_-> b_string。所以我想我會創建一個全局的「空B對象」:const B null_b。但我不能(自然)使用一個構造函數:

A(): b_(&null_b) {}; 

因爲B_不能指向一個const變量。如果不是「空B對象」,b_需要指向可變B對象。

使全局非常量解決問題,但我想保護常量,所以我可以保證「空對象」永遠不會改變。

FWIW,這涉及一個大型項目,其中b_指向另一個類中B對象的向量。我可以向該矢量添加一個空B對象,但這會讓我覺得它很糟糕。

有沒有解決我的問題的方法或模式?

+1

我可能不應該建議這個,但... const_cast? – Borgleader

+0

您是否在尋找Flyweight?但是,請記住,所有的指針在邏輯上會是const – sehe

+0

@Borgleader這對此有何幫助?你不能在運行時決定const_cast指針爲const(如果它指向你的Nil對象) – sehe

回答

5

而不是持有一個指向B對象的指針,而是用虛方法創建一個基類並存儲指向它的指針。從中導出B類和Null_B類,但不要讓Null_B上的方法進行修改。現在,即使您的Null_B對象不是const,也無所謂。

作爲額外的保護層,您可以嘗試修改對象引發的異常,以便檢測並找到您的邏輯錯誤。

+1

一個工作示例(除了直接從B獲得Null_B之外):https://ideone.com/m5ezfh – Bill

+0

@bill和markransom - 謝謝你的工作。感謝代碼比爾!它立即變得明顯。 :) –

1

嗯,也許它完全沒有關係,但是......你可以使用B的實例而不是指向B中的指針嗎?這將解決潛在的nullptr解引用問題。如果B太大,那麼你可以在它周圍創建一個輕量級的包裝器,並在A中存儲該包裝器的實例。如果B是nullptr,包裝器將爲你提供一些有意義的東西。

+0

不 - 我必須指出在真實項目中這個相當複雜的結構。我不僅需要複製的開銷,而且需要更新它而不是複製。 –

+0

感謝您的幫助!我認爲,馬克和比爾的解決方案本質上是對你所暗示的空對象的簡短而甜蜜的包裝。 –

3

const對象上不能有「非常量」指針點。不幸的是,使用const_cast刪除對象的const將意味着稍後的某些代碼可以嘗試修改該對象。 (請注意,除非原始對象是非常量,否則它是未定義的行爲,因此在技術上,允許編譯器在發生這種情況時生成崩潰代碼。不幸的是,很多情況下,當對象是某種東西時它不會崩潰比const char *const int []更復雜 - 允許代碼在覆蓋不想寫入的對象後繼續運行)。

然而,由於B類有一個b_string_成員是私有的,沒有外界的對象可以觸摸它,所以你可以確保b_string_任何使用通過虛函數(或多個虛擬函數)來完成,然後派生另一個從B的類中,當代碼嘗試修改派生對象中的b_string時,虛函數會顯示「對不起,你不能這樣做」。

+0

const_cast首先是UB,除非你知道指針實際上是可變的 – sehe

+0

是的,我的觀點是,如果你拋棄了常量,它不會阻止某人修改它 - 它是UB是一種旁邊的指向那個階段,因爲使它成爲'const'的原因可能是你不想修改它 - 在大多數系統中它是平均的,它可能不會崩潰,所以它會幸福地與對象一起工作無障礙和奇怪的事情發生。 –

+1

修改它可能會很好地崩潰應用程序。事實上,當你** [在平均hello-world級別應用程序中通過'const char *'寫入](http://ideone.com/30zoCA)**時,情況就是如此。我想我的觀點是「UB永遠不會離題」 – sehe

相關問題