Я имею дело с большой кодовой базой, в которой есть много классов и множество абстрактных методов для этих классов. Меня интересует мнение людей о том, что мне делать в следующей ситуации.
Если у меня есть класс Parent-A с абстрактным методом. Будет только 2 ребенка. Если Child-B реализует AbstractMethodA, а Child-B нет, поскольку он не применяется.
Нужно ли мне
Обновлено: спасибо за все ответы. Это подтвердило мои подозрения, что этого не должно происходить. После дальнейшего расследования выяснилось, что эти методы вообще не использовались, поэтому я полностью их удалил.





сделать его виртуально пустым в базовом классе и переопределить в дочерних.
Если AbstractMethodA не применяется к Child-B, то Child-B не должен наследовать от Parent-A.
Или взять контрапозитив, если Child-B наследуется от Parent-A, а AbstractMethodA не применяется к дочернему, то его тоже не должно быть в родительском.
Помещая метод в Parent-A, вы говорите, что метод применяется к Parent-A и всем его дочерним элементам. Вот что такое наследование средства, и если вы используете его для обозначения чего-то другого, вы столкнетесь с серьезным спором со своим компилятором.
[Изменить - тем не менее, ответ Младена Прайдича прекрасен, если метод действительно применяется, но не должен ничего делать для одного или нескольких задействованных классов. Метод, который ничего не делает, - это ИМО, это не то же самое, что метод, который неприменим, но, возможно, мы не имеем в виду то же самое, говоря «не применяется»]
Другой способ - все равно реализовать метод в Child-B, но заставить его делать что-то радикальное, например, всегда возвращать ошибку, или генерировать исключение, или что-то в этом роде. Это работает, но его следует рассматривать как нечто вроде уловки, а не как чистый дизайн, поскольку это означает, что вызывающие абоненты должны знать, что то, что у них есть, что они рассматривают как Parent-A, является В самом деле дочерним-B и, следовательно, они не должен вызывать AbstractMethodA. По сути, вы отказались от полиморфизма, который является основным преимуществом объектно-ориентированного наследования. Лично я предпочитаю делать это таким образом, чем иметь реализацию, генерирующую исключение в базовом классе, потому что тогда дочерний класс не может «случайно» вести себя плохо, «забыв» реализовать метод вообще. Он должен его реализовать, и если он реализует его так, чтобы не работать, он делает это явно. Плохая ситуация должна быть шумной.
Вы можете использовать интерфейсы. Тогда Child-A и Child-B могут реализовать разные методы и по-прежнему наследовать от Parent-A. Интерфейсы работают как абстрактные методы в том смысле, что заставляют класс реализовывать их.
Если реализация в потомках не является обязательной, вы должны выбрать 1 + 2 (т.е. пустой виртуальный метод в предке)
Если некоторые подклассы (B1, B2, ...) A используются для другого подмножества его методов, чем другие (C1, C2, ...), можно сказать, что A можно разделить на B и C.
Я не слишком хорошо знаю Delphi (совсем не :)), но я подумал, что так же, как, например, в Java и COM класс может «реализовывать» несколько интерфейсов. В C++ этого можно добиться только путем многократного наследования абстрактных классов.
Более конкретно: я бы создал два абстрактных класса (с абстрактными методами) и изменил бы дерево наследования.
Если это невозможно, обходным путем может быть «Адаптер»: промежуточный класс A_nonB_ со всеми реализованными пустыми методами B (и выдача предупреждения при их вызове) и A_nonC_. Затем измените дерево наследования, чтобы решить вашу проблему: B1, B2, ... наследуются от A_nonC_ и C1, C2, ... наследуются от A_NonB_.
Я думаю, что, вообще говоря, вы не должны наследовать от абстрактного класса, если вы не можете реализовать все абстрактные методы в первую очередь, но я понимаю, что есть некоторые ситуации, в которых все еще имеет смысл сделать это (см. класс Stream и его реализации).
Я думаю, вам следует просто создать реализации этих абстрактных методов, которые генерируют NotImplementedException.
Вы также можете попробовать использовать ObsoleteAttribute, чтобы вызов этого конкретного метода приводил к ошибке времени компиляции (конечно, помимо выброса NotImplementedException). Обратите внимание, что ObsoleteAttribute не совсем предназначен для использования для этого, но я думаю, что если вы используете значимое сообщение об ошибке с комментариями, все в порядке.
Пример обязательного кода:
[Obsolete("This class does not implement this method", true)]
public override string MyReallyImportantMethod()
{
throw new NotImplementedException("This class does not implement this method.");
}