2015-06-02 55 views
0

假設我有一個父類class Parent和兩種類型的子對象class Sonclass Daughter。這是常見的SonDaughter 屬性在ParentC++共享子對象之間的父屬性

定義現在我定義的Son一個實例和Daughter之一。他們有不同的 方法,可以做不同的事情,但當Son做些什麼,Daughter 等待(和相互)。 SonDaughter的行爲是 重新定義Parent中的一些屬性, 兩個孩子都應該考慮到這些屬性。

實現了最初的想法是這些屬性設置爲static所以如果 Daughter改變的東西,它也會影響Son。但我的問題是, 它會影響所有SonDaughter的實例,我只想影響 那些在同一個「家庭」。

這裏是暴露我的問題一個僞代碼:

class Parent{ 
    public: 
    /*define some constructors and parent stuff*/ 

    void set_family_name(std::string f){ family_name = f; } 

    protected: 
     std::string family_name; 
} 

class Son : public Parent{ 
    public: 
    /*define some constructors and son stuff*/ 
} 

class Daughter : public Parent{ 
    public: 
    /*define some constructors and daughter stuff*/ 
} 

int main(){ 
    Son JohnSmith(/*some attributes*/); 
    Daughter AnnaSmith(/*some attributes*/); 

    Son BobWeston(/*some attributes*/); 

    JohnSmith.set_family_name("Smith"); /*should also affect AnnaSmith but not BobWeston*/ 
} 

是否有連接子的兩個實例的方式,這樣,當一個改變 父參數將反映在另一個但不是在他們全部 ?

我想到的第一個解決方案是設置一些其他類, class FamilyAttribute將在Parent中引用。喜歡的東西:

class FamilyAttribute{ 
    public: 
    /*define some constructors and family stuff*/ 

    void set_family_name(std::string f){ family_name = f; } 

    private: 
     std::string family_name; 
} 

class Parent{ 
    public: 
    /*define some constructors and parent stuff*/ 

    void set_family_name(std::string f){ attribute->set_family_name(f); } 

    protected: 
     FamilyAttribute* attribute; 
} 

但是,這將讓我重寫所有的方法,這也將成倍的數量 的方法的調用。這也似乎很奇怪,因爲現在Parent只有 多態性(我需要)。

有沒有更好的方法?

+0

這聽起來像是一個可怕的混亂的層次結構,違反了Liskov替代原則。你是否真的試圖模仿家庭關係,比如父母/孩子,還是你只是用一個可怕的比喻來描述你真正的問題?有了這個模型一個兒子IS-A家長,這似乎是錯誤的。 –

+0

@JonathanWakely糟糕的例子,我的壞!對不起(可以用親屬取代父母:-)) – PinkFloyd

+0

這是一個可怕的例子,因爲你以兩種不同的方式使用「父母」和「孩子」,一種是普通的面向對象的「父類」和「子類」術語我討厭它,它會引起誤解,最好談論基類和派生類),另一種方式是在談論人類家庭關係。 –

回答

2

C++支持多種共享變量的方式,但它們都不允許您控制按實例進行實例共享。該語言不知道「家庭」的概念,所以你必須自己構建它。

您的解決方案在Parent中引入了常見的FamilyAttribute是正確的。您可能想要調整實施,例如通過將類重命名爲Family,或者用引用替換指針,但方向是絕對正確的:您需要定義一個單獨的類來表示共享數據,並根據需要配置共享族的實例。

請注意,您的SonDaughterParent獲得實施很可能有缺陷的,因爲公共派生建議SonDaughter可以作爲一個Parent(見Liskov Substitution Principle)。爲了捕獲Son s和Daughter s中常見的內容而不考慮其性別,您應該將Parent類重命名爲Child

+0

謝謝!我會研究這個方向!仍然有一個問題與你的答案有關。爲什麼以及如何通過引用來替換指針? – PinkFloyd

+0

別的,將單獨的類定義爲嵌套類會好嗎? – PinkFloyd

+1

@PinkFloyd使用引用代替指針會向代碼的讀者建議共享的東西不是可選的(因爲引用不能合法地設置爲NULL)。如果它是與類緊密相關的實現細節(即'FamilyAttribute'),則嵌套共享類可能是一個好主意。如果你決定讓它成爲所有人都可以得到的頭等公民,即「家庭」,那麼它應該仍然是一個頂級的課程。 – dasblinkenlight

2

有沒有辦法連接兩個孩子的實例,以便當一個父母的參數改變時,它反映在另一個,但不是所有這些實例?

不自動在類型系統中,沒有。

沒有辦法將某些類型的實例連接到某個類型的其他任意實例,而無需使用類似指針的連接。

看來你想要塑造的是Person,具有兩種類型的具體子類,兒子和女兒(或男人和女人),所以兒子是一個人,女兒是一個人。

家族名稱是一個屬性,應該使用HAS-A關係建模,以便Person HAS-A指向FamilyName對象的指針以及多個Person對象可以引用相同的FamilyName。 (A shared_ptr將是建模的最佳方式,以便所有權得到正確管理)。

但是,這將使我重寫所有的方法,這也會增加方法調用的數量。

這是不可能的,因爲你沒有顯示任何方法,所以不可能知道它爲什麼會導致你重寫它們。

這似乎也很奇怪,因爲現在Parent只對多態(我需要)有用。

要麼我不明白你的意思,要麼我不明白爲什麼這很奇怪,或者爲什麼這是一個問題。如果你需要多態性,爲什麼有一個提供多態接口的基類很奇怪?

+0

再次,我同意你的觀點,我的例子是一個糟糕的例子......爲了回答你的最後一點,我不認爲有一個提供多態接口的基類是很奇怪的,我的意思是它現在是它唯一的角色,因爲所有的「硬」工作被重新分配給「FamilyAttribute」。 – PinkFloyd

+0

那麼,如果你需要將「工作」作爲在不同實例之間共享的東西,那麼它必須在父母之外完成。 –

0

你可以介紹以下的私有成員基類:

static std::map<FamilyId, FamilyAttributes> FamilyPropertyMap; 

FAMILYID將是一個的typedef要通過你們的家庭進行排序的唯一標識符;也許只是一個名字的字符串,也許是別的。 FamilyAttributes將是一個存儲公共數據的對象,即具有相同「族」的所有派生對象都希望共享訪問權。首先,一個存儲所有變量的結構,您想要共同訪問,可能就足夠了。

然後你可以在下面的公共或受保護的方法添加到基類:

FamilyAttributes& getMyFamiliesAttributes(){return FamilyPropertyMap[family_name];} 

我假設你使用的字符串作爲FAMILY_NAME鍵映射在這裏。 通過這種方式,您可以將所有派生對象的訪問權限限制爲其特定「族」的數據。如果家庭以外的人能夠訪問家庭財產,則公開該方法,如果只有派生對象應該能夠在內部處理數據,請將其保護起來。

靜態映射可能不是最優雅的或OO解決方案,但它的優點是,您不必處理指針。確保在訪問地圖時正確初始化family_name字符串或檢查空字符串。