Каким должен быть прототип моей виртуальной функции? - PullRequest
2 голосов
/ 21 октября 2011

Допустим, у меня есть абстрактный базовый класс Base с виртуальной функцией doSomething()

Есть два производных класса, один из которых не принимает параметров в doSomething(), а другой - структуру ицелое число в качестве параметра.

Функция в другом классе (SomeClass) вызывает doSomething(), используя переменную Base*.Также необходимо передать параметры, которые я упомянул для DerivedTwo.

Как выбрать прототип без использования if-else для проверки класса объекта во время выполнения?

СпасибоВы.

    class Base {
      public:
      void virtual doSomething(); 
    }

    class DerivedOne : Base {
      public:
      void doSomething(int a,struct b);
    }

    class DerivedTwo : Base {
      public:
      void doSomething();
    }

Ответы [ 6 ]

2 голосов
/ 21 октября 2011

Вы хотите изменить список параметров виртуального метода в производном классе. Это не может быть сделано. Обычно, когда вы обнаруживаете, что хотите это сделать, это указывает на неверный дизайн иерархии классов.

Наивные попытки решить эту проблему обычно включают добавление чего-либо в базовый класс, что имеет смысл только для определенных производных классов. Это нарушает принципы хорошего дизайна.

Есть много разных способов решить проблему более правильно, но на основе этого искусственно созданного примера трудно дать совет.

2 голосов
/ 21 октября 2011

Если вам нужно передать эти переменные для обоих производных типов, просто объявите их везде одинаково, например:

class Base {
  public:
  void virtual doSomething(int a,struct b); 
}

class DerivedOne : Base {
  public:
  void doSomething(int a,struct b);
}

class DerivedTwo : Base {
  public:
  void doSomething(int a,struct b);
}

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

1 голос
/ 21 октября 2011

Один из способов сделать это будет:

class Base {
public:
    Base();
    virtual ~Base();
    virtual void doSomething();
};

class DerivedOne : public Base {
public:
    DerivedOne();
    void doSomethingElse(int a,struct b);
};

class DerivedTwo : public Base {
public:
    DerivedTwo();
    virtual void doSomething();
};

Затем вы можете использовать dynamic_cast для определения типа во время выполнения, поскольку у вас, похоже, есть условное выражение типа где-то в SomeClass. Методы не равны и принципиально различны. Кроме того, DerivedOne::doSomething будет скрывать Base::doSomething.

Обновление

Как уже говорили другие, часто неприятный запах, если ваша программа использует выражения с условными типами. Поскольку в вашем примере недостаточно контекста, чтобы предложить соответствующие решения, нам трудно помочь вам в этом отношении. Если вы заинтересованы в удалении условного типа, одним из многих возможных решений этой проблемы будет:

class Base {
public:
    Base();
    virtual ~Base();
    virtual void doSomething();
};

class DerivedOne : public Base {
public:
    DerivedOne();
    // ...
    virtual void doSomething(); // << no parameters required.
                                // they have moved to member data:
private:
    int a;
    b another;
};

class DerivedTwo : public Base {
public:
    DerivedTwo();
    virtual void doSomething();
};

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

0 голосов
/ 07 октября 2013

По аналогии с примером Тараса ... просто добавьте «значения по умолчанию» к прототипу Base и DerivedTwo в примере Тараса. Таким образом, оставшаяся часть кода, использующего базовый класс или класс DerivedTwo, не должна будет меняться.

0 голосов
/ 07 октября 2013

в вашем примере вы можете использовать RTTI вместо if / else, чтобы создать экземпляры DerivedOne и DerivedTwo, а затем привести базовый указатель к обоим (DerivedOne и DerivedTwo), чтобы в результате один из них был равен NULL. затем вы проверяете, является ли нужный производный объект не пустым, и если это так, вы вызываете функцию:

DerivedOne *pDrvOne=dynamic_cast<DerivedOne*>(pBase);
DerivedTwo *pDrvTwo=dynamic_cast<DerivedTwo*>(pBase);
then: if(pDrvOne)pDrvOne->deSo,ething(a,b); if(pDrvTwo) pDrvTwo->doSomething();

* Помните, что использование RTTI подорвет принципы полиморфизма. в вашем примере вы не перегружали doSomething () в подклассе DerivedOne: «перегрузить функцию - это использовать одну и ту же сигнатуру (имя функции и то же число и тип параметров)». но вы просто перегружаете его в DerivedTwo. таким образом рассмотрим этот пример:

Base *pBs;
pBs=new DerivedOne; pBs->doSomething(a,b); the result a call to base doSomthing!!!

* Решение состоит в том, чтобы попытаться понять проблему, которую собирается решить ваш класс.

0 голосов
/ 29 января 2013

Можем ли мы решить эту проблему следующим образом? :

class Base {
  public:
  void virtual doSomething();
  void virtual doSomething(int a,struct b); 
}

class DerivedOne : Base {
  public:
  void doSomething(int a,struct b);
}

class DerivedTwo : Base {
  public:
  void doSomething();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...