Переопределение метода C ++ в конкретном классе - PullRequest
9 голосов
/ 04 ноября 2011

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

Я также рассмотрел шаблон метода шаблона, но это не совсем то, что я ищудля любого.

Ответы [ 5 ]

3 голосов
/ 04 ноября 2011

Я предполагаю, что вы ищете принудительное выполнение этого условия во время компиляции (спасибо @Chad за указание на это)

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

Я думаю, что то, что вы говорите, указывает на проблему дизайна в вашем программном обеспечении.Допустим, вы хотите принудительно переопределить метод foo () всеми классами inherirhing в следующем фрагменте

class BaseButConcrete
{
    ... //Common stuff
    ... //

    virtual void foo()
    { /*implementation that you do not want to be inherited, but will be...*/ }
}

class DerivedOtherConcrete : public BaseButConcrete
{
    void foo()
    { /*different implementation, 
      but no obligation from compiler point of view*/ }
}

Я не вижу хорошей причины для разработки, почему все общие элементы не могут быть перемещены в абстрактномБазовый класс. Из того, что вы описываете , вы не хотите наследовать реализацию foo в Derived, поэтому не наследуйте эту часть!Таким образом, очень классический дизайн должен сработать:

class AbstractBase
{
    ... //Common stuff has moved here
    ... //
    virtual void foo() =0;
}

class NotAnymoreBaseButStillConcrete : public AbstractBase
{
    void foo()
    { /*implementation that should not be inherited,
      and that will not by design*/ }
}

class DerivedOtherConcrete : public AbstractBase
{
    void foo()
    { /*different implementation, 
      now mandatory compiler-wise for the class to be concrete*/ }
}

Таким образом, общий материал все еще распределяется между всеми вашими производными классами, и вы сохраняете то, что не хотите наследовать (то есть Реализация foo ) разделена на классы не по одному и тому же пути наследования.

1 голос
/ 17 ноября 2017

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

class MyBaseClass
{
protected:
   virtual void MyOverrideFunction(void)
   {
      ASSERT(false); // this function must be overridden
   }
}
1 голос
/ 04 ноября 2011

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

Необычное обобщение этого подхода состоит в том, чтобышаблон класса, который должен использоваться для создания конкретного класса из каждого абстрактного класса.Например, он может предоставить метод clone.Или, в Microsoft ATL, он обеспечивает реализацию интерфейса IUnknown.

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

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

Однако, обобщая вашу проблему, вы обобщили ответы.

Приветствия & hth.,

1 голос
/ 04 ноября 2011

Один из вариантов - поместить всю реализацию класса в абстрактный суперкласс и наследовать от него.

  • Переместите всю реализацию вашего конкретного класса T в абстрактный класс S.
  • В S, сделайте обязательный переопределенный метод чистой виртуальной функцией - и дайте определение его.
  • T подклассов S.
  • В T переопределите функцию, которая должна быть переопределена, и вызовите реализацию S.
  • Вместо подкласса T, подкласс S.
  • Предотвращение подклассов T.
0 голосов
/ 04 ноября 2011

Нет, это невозможно. Если вы хотите заставить (во время компиляции) производный класс определять виртуальную функцию, тогда его базовый класс должен быть абстрактным, или, другими словами, базовый класс должен иметь чисто виртуальную функцию. Абстрактный класс (с чисто виртуальными функциями) не может быть конкретным, то есть вы не можете создать его экземпляр.

...