В ответах на этот вопрос общее согласие заключалось в том, что статические методы не предназначены для переопределения (и, следовательно, статические функции в C # не могут быть виртуальными или абстрактными). Это не только случай в C #, хотя; Java также запрещает это, и C ++, похоже, тоже не нравится. Однако я могу вспомнить множество примеров статических функций, которые я хотел бы переопределить в дочернем классе (например, фабричные методы). Хотя в теории есть способы обойти их, ни один из них не является чистым или простым.
Почему статические функции не должны переопределяться?
object-oriented-design
abstract-class
static-methods
PixelArtDragon
источник
источник
self
указатель, который указывает на класс, а не на экземпляр класса.Ответы:
В статических методах нет объекта, обеспечивающего надлежащее управление механизмом переопределения.
Обычный механизм виртуальных методов класса / экземпляра позволяет точно настроить управление переопределениями следующим образом: каждый реальный объект является экземпляром ровно одного класса. Этот класс определяет поведение переопределений; он всегда получает первую трещину в виртуальных методах. Затем он может выбрать вызов родительского метода в нужное время для его реализации. Каждый родительский метод также получает свою очередь для вызова своего родительского метода. Это приводит к хорошему каскаду родительских вызовов, который реализует одно из понятий повторного использования кода, которым известна объектная ориентация. (Здесь код базовых / суперклассов повторно используется относительно сложным способом; другое ортогональное понятие повторного использования кода в ООП - это просто наличие нескольких объектов одного и того же класса.)
Базовые классы могут повторно использоваться различными подклассами, и каждый может комфортно сосуществовать. Каждый класс, который используется для создания экземпляров объектов, диктует свое поведение, мирно и одновременно сосуществуя с другими. Клиент может контролировать, какое поведение он хочет и когда, выбирая, какой класс использовать для создания экземпляра объекта и передачи другим по желанию.
(Это не идеальный механизм, так как всегда можно определить возможности, которые не поддерживаются, конечно, поэтому шаблоны, такие как фабричный метод и внедрение зависимостей, размещены сверху.)
Таким образом, если бы мы сделали возможность переопределения для статики без изменения чего-либо еще, у нас были бы трудности с упорядочением переопределений. Было бы трудно определить ограниченный контекст для применимости переопределения, поэтому вы получите переопределение глобально, а не локально, как с объектами. Не существует экземпляра объекта для переключения поведения. Итак, если кто-то вызвал статический метод, который, как оказалось, был переопределен другим классом, переопределение получит контроль или нет? Если есть несколько таких переопределений, кто получает контроль первым? второй? С переопределением объекта экземпляра у всех этих вопросов есть значимые и аргументированные ответы, но со статикой они не имеют.
Переопределения для статики были бы в значительной степени хаотичными, и подобные вещи делались раньше.
Например, в Mac OS System 7 и более ранних версиях использовался механизм исправления ловушек для расширения системы путем получения контроля над системными вызовами приложений перед операционной системой. Вы можете думать о таблице исправлений системного вызова как о массиве указателей на функции, во многом как vtable для объектов экземпляров, за исключением того, что это была одна глобальная таблица.
Это вызвало невыразимое горе для программистов из-за неупорядоченного характера исправления ловушек. Тот, кто в последний раз исправлял ловушку, в основном выиграл, даже если не хотел. Каждый патч ловушки будет захватывать предыдущее значение ловушки для своего рода возможности родительского вызова, которая была чрезвычайно хрупкой. Удаляя патч-ловушку, скажем, когда вам больше не нужно было знать, что системный вызов считается дурным тоном, поскольку у вас не было информации, необходимой для удаления вашего патча (если вы сделали это, вы также удалили бы все остальные патчи, которые следовали вы).
Это не означает, что было бы невозможно создать механизм для переопределений статики, но я бы предпочел вместо этого превратить статические поля и статические методы в поля экземпляров и методы экземпляров метаклассов, чтобы обычный объект затем будут применяться методы ориентации. Обратите внимание, что существуют системы, которые делают это также: CSE 341: классы Smalltalk и метаклассы ; Смотрите также: Что такое Smalltalk-эквивалент статики Java?
Я пытаюсь сказать, что вам нужно сделать серьезный языковой дизайн, чтобы он работал даже достаточно хорошо. Для одного примера был сделан наивный подход, который хромал, но был очень проблематичным и, возможно, (то есть, я бы поспорил) архитектурным недостатком, предоставив неполную и сложную в использовании абстракцию.
К тому времени, когда вы закончите разработку функции статических переопределений для правильной работы, вы, возможно, только что изобрели некоторую форму метаклассов, которая является естественным расширением ООП в / для основанных на классах методов. Таким образом, нет никаких причин не делать этого - и некоторые языки на самом деле делают. Возможно, это всего лишь более ограниченное требование, которое многие языки предпочитают не выполнять.
источник
this.instanceMethod()
имеет динамическое разрешение, поэтому, если уself.staticMethod()
него такое же разрешение, а именно динамическое, он больше не будет статическим методом.Переопределение зависит от виртуальной диспетчеризации: вы используете тип времени выполнения
this
параметра, чтобы решить, какой метод вызывать. Статический метод не имеетthis
параметров, поэтому отправлять нечего.Некоторые языки, в частности Delphi и Python, имеют промежуточную область видимости, которая допускает это: методы класса. Метод класса не является обычным методом экземпляра, но он также не является статическим; он получает
self
параметр (забавно, что оба языка называют этотthis
параметрself
), который ссылается на сам тип объекта, а не на экземпляр этого типа. С этим значением теперь у вас есть тип, доступный для виртуальной отправки.К сожалению, ни у JVM, ни у CLR нет ничего похожего.
источник
self
Являются ли языки, которые используют , имеют классы в качестве актуальных, созданных объектов с переопределяемыми методами - конечно, Smalltalk, Ruby, Dart, Objective C, Self, Python? По сравнению с языками, которые берут после C ++, где классы не являются объектами первого класса, даже если есть некоторый доступ к отражению?virtual
и затем переопределен в классе-потомке, как методы экземпляра.Ты спрашиваешь
я спрашиваю
Определенные языки заставляют вас начать показ в статическом методе. Но после этого вы действительно можете решить очень много задач без каких-либо статических методов.
Некоторые люди любят использовать статические методы каждый раз, когда в объекте нет зависимости от состояния. Некоторые люди любят использовать статические методы для построения других объектов. Некоторым людям по возможности нравится избегать статических методов.
Никто из этих людей не прав.
Если вам нужно, чтобы он был перезаписываемым, просто перестаньте обозначать его как статический. Ничто не сломается, потому что вокруг вас летает объект без гражданства.
источник
_start()
символ в Linux). В этом примере исполняемый файл - это объект (он имеет свою собственную «таблицу диспетчеризации» и все остальное), а точка входа - это динамически отправляемая операция. Следовательно, точка входа в программу является виртуальной, если смотреть на нее снаружи, и ее можно легко сделать виртуальной, если смотреть на нее изнутри.Это не вопрос «должен».
«Переопределение» означает «отправка динамически ». «Статический метод» означает «отправка статически». Если что-то статично, оно не может быть переопределено. Если что-то может быть переопределено, это не статично.
Ваш вопрос довольно похож на вопрос: «Почему трицикл не должен иметь четыре колеса?» Определение из «трехколесного велосипеда» является то , что имеет три колеса. Если это трехколесный велосипед, у него не может быть четырех колес, если у него четыре колеса, это не может быть трехколесный велосипед. Аналогично, определение «статического метода» состоит в том, что он статически рассылается. Если это статический метод, он не может быть динамически отправлен, если он может быть динамически отправлен, это не может быть статический метод.
Конечно, вполне возможно иметь методы класса, которые могут быть переопределены. Или у вас может быть такой язык, как Ruby, где классы являются объектами, как и любой другой объект, и, таким образом, могут иметь методы экземпляров, что полностью исключает необходимость в методах классов. (У Ruby есть только один вид методов: методы экземпляра. У него нет методов класса, статических методов, конструкторов, функций или процедур.)
источник
В C # вы всегда вызываете статические члены, используя класс, например
BaseClass.StaticMethod()
, нетbaseObject.StaticMethod()
. Таким образом, в конечном итоге, если у вас естьChildClass
наследование отBaseClass
иchildObject
экземплярChildClass
, вы не сможете вызывать свой статический метод изchildObject
. Вам всегда нужно явно использовать реальный класс, так чтоstatic virtual
просто не имеет смысла.Что вы можете сделать, это переопределить тот же
static
метод в вашем дочернем классе и использоватьnew
ключевое слово.Если бы можно было позвонить
baseObject.StaticMethod()
, тогда ваш вопрос имел бы смысл.источник