2014-12-22 92 views
2

我有下面的類:以下場景使用哪種模式?

class Base { 
public: 
    Base(string name) { 
     agg = new Aggregate(name); 
    } 
private: 
    Aggregate* agg; 
}; 

現在我需要擴展這個類:

class Derived : Base { 
public: 
    Derived(string name) : Base(name) { 
     agg2 = new Aggregate2(name); 
    } 
private: 
    Aggregate2* agg2; 
}; 

我想要的是當我創建一個Base對象,Aggregate需要創建,當我創建應該創建一個Derived對象只有Aggregate2

現在,這是不會發生,因爲它的Aggregate當我創建一個Derived對象也就是所謂的構造函數中像這樣AggregateAggregate2將創建創建。

我可以將創建移動到不同的方法,並在創建對象後調用它。
有沒有其他優雅的方式來做我想要的?

+0

爲什麼不創建一個單獨的,不受保護的構造函數? – Rufflewind

+3

那麼,當你創建'Derived'你想離開'agg'未初始化?你可以做到這一點,例如使用Rufflewind的建議,但聽起來你正試圖將[Liskov Substitution Principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle)打破給我,這通常是一個壞主意。 –

+1

[OT]:你應該使用'std :: unique_ptr agg;'而不是原始擁有指針。 – Jarod42

回答

6

您可以使用以下:

class Base { 
public: 
    explicit Base(string name) : agg(new Aggregate(name)) {} 
protected: 
    Base() = default; 
private: 
    std::unique_ptr<Aggregate> agg; 
}; 

class Derived : Base { 
public: 
    // implicit call to Base(), you may be explicit if you want 
    Derived(string name) : agg2(new Aggregate2(name)) {} 
private: 
    std::unique_ptr<Aggregate2> agg2; 
}; 
+0

這就是OP想要的,所以+1。但是,如果創建帶有未初始化的'agg'的'Base'並不好。我不明白爲什麼創建一個派生自'Base'和未初始化'agg'的東西應該是可以的。 –

+0

@ChrisDrew:'agg'默認是用'nullptr'值初始化的。 – Jarod42

+0

的確,我喜歡使用'unique_ptr'的建議,這是好處之一。但事實是,如果沒有非空的'Aggregate',你就無法創建原始的'Base'。隨着你的建議你可以,所以'基地'的一些原始行爲可能被打破。 –

0
嘗試

此代碼

class Base { 
public: 
    Base() { } 
    Base(string name) { 
     agg = new Aggregate(name); 
    } 
    void setName(string name) { 
     agg = new Aggregate(name); 
    } 
private: 
    Aggregate* agg; 
}; 

class Derived : Base { 
public: 
    Derived(string name) { 
     agg2 = new Aggregate2(name); 
    } 
private: 
    Aggregate2* agg2; 
}; 
+0

這有效。但是Base()的默認構造是允許的,這會使構造Base類的Aggregate不受構造。 – Jagannath

+0

@Jagannath是的,默認的'Base'構造函數應該是'protected'。有些解釋文字會很好。 –

0

您可以在Base類的字符串型的數據成員;它可以賦值(與構造函數中的名稱相同),並且您可以在派生類中訪問它(也可以使其受保護)以初始化agg2。

0

我會用一個構造函數重載此:

class Base { 
    public: 
     Base(string name) : agg(new Aggregate(name)) {} 
    protected: 
     Base(Aggregate* agg) : agg(agg) {} //Base will take possession of the passed pointer. 
    private: 
     std::unique_ptr<Aggregate> agg; 
}; 

class Derived : Base { 
    public: 
     Derived(string name) : Base(new Aggregate2(name)) {} 
}; 

注:
這假定Aggregate2Aggregate的。這個假設是基於這樣一個事實,即派生類中的基類的移除能力至少是一種非常強烈的代碼味道。所以我得出結論,兩個聚合基本上都起着相同的作用,所以第二個變量用於保存Aggregate2實例是多餘的,而Aggregate2Aggregate的子類,以便將行爲與關係進行匹配。

+0

這裏假設'Aggregate2'來源於'Aggregate'。 –

+0

@ChrisDrew對。我添加了一個說明,解釋我的結論飛躍。 – cmaster

+0

這是正確的,我忘了提到Aggregate2是從Aggregate – Kobe

1

這是你不應該做的事情。如果你的第二類是不應該有第一聚合成員,那麼正確的做法是使兩個獨立的類和使用繼承:

class Foo1 { ... }; 
class Foo2 { ... }; 

現在,如果你真的一個理由使用繼承你有幾個選擇:
- 使用Foo1和Foo2派生的基類。基類只包含Foo1和Foo2共有的內容。您需要的聚合分別進入Foo1和Foo2。 (推薦
- 讓Foo1有工會成員(如果你知道原因和工會wherefores):

union Bla { std::unique_ptr<Agg1> a1; std::unique_ptr<Agg2> a2; }; 

而且,我也要着重強調,我很難想到一個例子,其中的第二個版本是有意義的...去一個單獨的基類!