2014-12-30 3 views
2

Я довольно часто сталкиваюсь с этой проблемой. Скажем, у меня есть эти классы:Наследование отношения композиции в C++

class B 
{ 
    public: 
    virtual std::string className(){return "B";} 
}; 

class A 
{ 
    public: 
    A() 
    : _B(new B) 
    {} 

    virtual std::string className(){return "A";} 

    virtual void desc() 
    { 
     std::cout << "I am " << className() << 
     " and I own: " << _B->className() << std::endl; 
    } 

    protected: 
    B * _B; 
}; 

Затем я хочу продлить A и B с новой информацией. Я уверен, что SuperA и SuperB имеют отношение «is-a» с A и B, соответственно. Простым способом было бы сделать наследование попробовать:

class SuperB: public B 
{ 
    public: 
    virtual std::string className(){return "SuperB";} 
} 

class SuperA: public A 
{ 
    public: 
    SuperA() 
    : A() 
    , _superB(new SuperB) 
    {} 

    virtual std::string className(){return "SuperA";} 

    virtual void desc() 
    { 
     std::cout << "I am " << className() << 
     " and I own: " << _superB->className() << std::endl; 
    } 
    protected: 
    SuperB * _superB; 
}; 

Но это, очевидно, не очень хорошо, так как SuperA бы фактически два B S: один из A класса, а другой из его SuperB класса. И переопределение desc не так изящно.

я могу видеть, что я мог бы сеттера и добытчики на B* в A и переопределить их в SuperA использовать SuperB вместо B, и никогда не отношусь к к B* непосредственно и всегда использовать сорбент, но это, кажется, немного навязчивый для A.

Пытаться составить, то есть иметь SuperA, владеющий экземпляром A*, также не выглядит лучше.

И еще сложнее, если A не владеет ни одним B*, но скажем std::vector<B*>.

Это обычная проблема? Есть ли элегантное решение, которое я не вижу для него?

+0

Почему вы не можете иметь защищенный c'tor в 'Ā' что принимает указатель 'B'? Затем используйте его для построения под-объекта 'A'' superA' с помощью 'superB'? – StoryTeller

+0

Вы можете использовать 'static_cast' или' dynamic_cast', где бы вы не использовали '_superB' в' SuperA'. Не элегантный, но, возможно, достаточно для ваших целей? – anatolyg

+0

@StoryTeller Это решение. Это немного интрузивно для A. – RedWark

ответ

5

Вы можете просто A иметь защищенный конструктор, который принимает B*:

class A { 
public: 
    A() 
    : _B(new B) 
    { } 

protected: 
    A(B* b) 
    : _B(b) 
    { } 
}; 

Так что:

class SuperA : public A { 
public: 
    SuperA() 
    : A(new SuperB) 
    { } 
}; 
+0

Я не думал об этом. Это решение на самом деле не является интрузивным и поддерживает вектор, который я вызвал во второй части моего вопроса! Благодаря! – RedWark

Смежные вопросы