C ++ дизайн запрос - PullRequest
       37

C ++ дизайн запрос

1 голос
/ 03 января 2012

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

#include <stdio.h>

class Module
{
  public:
    virtual void print()
    {
        printf("Inside print of Module\n");
    }
};
class ModuleAlpha : public Module
{
  public:
    void print()
    {
        printf("Inside print of ModuleAlpha\n");
    }
    void module_alpha_function()  /* local function of this class */
    {
        printf("Inside module_alpha_function\n");
    }
};
class System
{
  public:
    virtual void create_module(){}
   protected:
    class Module * module_obj;
};
class  SystemAlpha: public System
{
  public:
    void create_module()
    {
        module_obj = new ModuleAlpha();
        module_obj->print(); // virtual function, so its fine.

        /* to call module_alpha_function, dynamic_cast is required,
         * Is this a good practice or there is some better way to design such a system */
        ModuleAlpha * module_alpha_obj = dynamic_cast<ModuleAlpha*>(module_obj);
        module_alpha_obj->module_alpha_function();
    }
};

main()
{
   System * system_obj = new SystemAlpha();
   system_obj->create_module();
}

Редактировал код, чтобы он был более логичным, и он компилируется сразу.Вопрос в том, что есть лучший способ спроектировать такую ​​систему, или dynamic_cast является единственным решением.Кроме того, если есть больше производных модулей, то для приведения типов требуется некоторый интеллект в базовом классе Module.

Ответы [ 3 ]

0 голосов
/ 03 января 2012

Дизайн становится намного чище, если Base не содержит объект base_obj, а скорее получает ссылку через виртуальный метод. Derived должен содержать Derived2 объект, такой как:

class Base
{
  public:
      virtual void func1();
  private:
      class Base2;
      virtual Base2& get_base2();
};
class Derived : public Base
{
         Derived2 derived2;
   public:
         Base2& get_base2() { return derived2; }
         void DerivedFunc()
         {
              derived2->Derived2Func();
         }
}

Если вы беспокоитесь о производительности, передайте ссылку в конструкторе Base.

0 голосов
/ 03 января 2012

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

class Base2 {
  public:
     virtual void Derived2Func(){
     }
};

Base2* fnToInstantiateABase2();

class Base {
  public:
     Base()  : base2_obj(fnToInstantiateABase2()) {
     }
     virtual void DerivedFunc() {
     }
  protected:
     Base2* base2_obj;
};
class Derived : public Base {
  public:
     void DerivedFunc() {
        base2_obj->Derived2Func(); // not possible as base2_obj is of type Base2
     }
};


class Derived2 : public Base2 {
  public:
     void Derived2Func() {
     }
};


void test() {
  Base * base_obj = new Derived();
  base_obj->DerivedFunc();
}

Base2* fnToInstantiateABase2() {
  return new Derived2();
}
0 голосов
/ 03 января 2012

Если Derived является единственным конкретным экземпляром Base, вы можете использовать вместо него static_cast.

Лично я определяю функцию, например, MyCast для каждого специализированного класса.Я определяю четыре перегруженных варианта, чтобы я мог понижать константные и неконстантные указатели и ссылки.Например:

  inline Derived       * MyCast(Base       * x) { return static_cast<Derived *>      (x); }
  inline Derived const * MyCast(Base const * x) { return static_cast<Derived const *>(x); }
  inline Derived       & MyCast(Base       & x) { return static_cast<Derived &>      (x); }
  inline Derived const & MyCast(Base const & x) { return static_cast<Derived const &>(x); }

И также для Derived2 и Base2.

Большим преимуществом наличия всех четырех является то, что вы не сможете случайно изменить константу и можете использовать одну и ту же конструкцию независимоесли у вас есть указатель или ссылка.

Конечно, вы можете заменить static_cast на макрос и использовать dynamic_cast в режиме отладки, а static_cast - в режиме выпуска.

Кроме того, приведенный выше код можно легко обернуть в макрос, что упрощает пакетное определение функций.

Используя этот шаблон, вы можете реализовать свой код следующим образом:

class Derived : public Base
{
public:
   virtual void func2() 
   { 
     base2_obj = new Derived2();
   }
   void DerivedFunc()
   {
     MyCast(base2_obj)->Derived2Func();
   }
}
...