2015-02-03 5 views
0

Допустим, у меня есть следующие иерархии классов:добавив метод производного класса и вызова из базового указателя

class A 
{ 
public: 
    virtual ~A(); 
}; 

class B : public A 
{}; 

class AUser 
{ 
public: 
    virtual ~AUser(); 
protected: 
    A* m_pA; 
}; 

class BUser : public AUser 
{}; 

Теперь я хочу добавить метод B который не имеет отношение к A и будет называться только от BUser.

class B : public A 
{ 
public: 
    void addedFunctionality() 
    { 
     // do something 
    } 
}; 

Для вызова добавлен метод У меня есть два варианта:

  1. Добавить пустой метод A:

    class A 
    { 
    public: 
        virtual ~A(); 
        void addedFunctionality() 
        { 
         // do nothing 
        } 
    }; 
    
    class BUser : public AUser 
    { 
        void useB() 
        { 
         m_pA->addedFunctionality(); 
        } 
    }; 
    
  2. вызов добавленный метод с использованием опущенными:

    class BUser : public AUser 
    { 
        void useB() 
        { 
         static_cast<B*>(m_pA)->addedFunctionality(); 
        } 
    }; 
    

Я знаю, что нужно избегать осколков, но мне не нравится первый вариант, так как он раздувает код A без причины.

Есть ли другая альтернатива дизайна?

+0

Может 'BUser' также "быть"' B'? (например, 'class B: virtual public A {void addedFunctionality() {}};' then 'class BUser: virtual public AUser, virtual public B' ..? – txtechhelp

+0

no,' BUser' - это просто пользователь, а не служба. –

+1

Во-первых, если вы не знаете, что у вас есть 'B', вы должны использовать' dynamic_cast' вместо 'static_cast'. Однако, если вы это знаете, вы можете также сохранить указатель на' B' для начала. Кроме того, вы можете использовать шаблон посетителя. Кроме того, сложно предложить вещи, не зная, что происходит. –

ответ

0

Самое простое решение выглядит следующим образом (также предложил Ulrich Eckhardt):

class AUser 
{ 
public: 
    AUser(A* a) 
    { 
     m_pA = a; 
    } 
protected: 
    A* m_pA; 
}; 

class BUser : public AUser 
{ 
public: 
    BUser(B* b) : AUser(b) 
    { 
     m_pB = b; 
    } 

    void useB() 
    { 
     m_pB->addedFunctionality(); 
    } 
protected: 
    B* m_pB; 
}; 

Менее чистые, но вы можете также рассмотреть это:

class BUser : public AUser 
{ 
public: 
    BUser(B* b) : AUser(b) 
    { 
    } 
    void useB() 
    { 
     getB()->addedFunctionality(); 
    } 
protected: 
    B *getB() 
    { 
     return dynamic_cast<B*>(m_pA); 
    } 

}; 
+0

С первым вариантом, может быть, лучше просто скрыть базовый указатель с помощью: 'class BUser: public AUSER {protected: B * m_pA}; ', no? –

+1

Или вы можете просто сделать его закрытым. –

+0

Когда нет причин для производного класса получать доступ к указателю базового класса, тогда частный путь. как AUser, так и BUser, кстати. Кроме того, он может (и sh ould!) инициализируется в списке инициализаторов, что даже позволяет сделать его постоянным. Также мелкая деталь во второй версии: dynamic_cast может не понадобиться (я бы добавил это в утверждение, хотя), потому что конструктор и оставшийся код могут гарантировать, что там хранятся только Bs. –

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