W odpowiedziach na to pytanie, ogólny konsensus był taki, że metody statyczne nie mają być nadpisywane (a zatem funkcje statyczne w języku C # nie mogą być wirtualne ani abstrakcyjne). Jest to jednak nie tylko przypadek w języku C #; Java również tego zabrania, a C ++ też to nie lubi. Mogę jednak wymyślić wiele przykładów funkcji statycznych, które chciałbym zastąpić w klasie potomnej (na przykład metody fabryczne). Chociaż teoretycznie istnieją sposoby na ich obejście, żaden z nich nie jest czysty ani prosty.
Dlaczego funkcje statyczne nie powinny być nadpisywane?
object-oriented-design
abstract-class
static-methods
PixelArtDragon
źródło
źródło
self
wskaźnik, który wskazuje na klasę, a nie na instancję klasy.Odpowiedzi:
W przypadku metod statycznych nie ma obiektu zapewniającego odpowiednią kontrolę mechanizmu nadpisywania.
Mechanizm wirtualnej metody normalnej klasy / instancji pozwala na precyzyjnie dostrojone sterowanie nadpisywaniem w następujący sposób: każdy rzeczywisty obiekt jest instancją dokładnie jednej klasy. Ta klasa określa zachowanie przesłonięć; zawsze dostaje pierwszy crack przy metodach wirtualnych. Następnie może wybrać wywołanie metody nadrzędnej we właściwym czasie w celu jej implementacji. Następnie każda metoda nadrzędna otrzymuje swoją kolej, aby wywołać metodę nadrzędną. Powoduje to ładną kaskadę wywołań nadrzędnych, która realizuje jedno z pojęć ponownego użycia kodu, z którego znana jest orientacja obiektowa. (W tym przypadku kod bazowy / superklasy są ponownie wykorzystywane w stosunkowo skomplikowany sposób; innym ortogonalnym pojęciem ponownego użycia kodu w OOP jest po prostu posiadanie wielu obiektów tej samej klasy.)
Klasy podstawowe mogą zostać ponownie wykorzystane przez różne podklasy i każda z nich może wygodnie współistnieć. Każda klasa używana do tworzenia obiektów dyktujących własne zachowanie, pokojowo i jednocześnie współistniejących z innymi. Klient ma kontrolę nad tym, jakich zachowań chce i kiedy, wybierając klasę, której ma użyć, aby utworzyć obiekt i przekazać go innym, zgodnie z potrzebami.
(To nie jest doskonały mechanizm, ponieważ zawsze można zidentyfikować funkcje, które nie są obsługiwane, oczywiście, dlatego właśnie wzorce, takie jak metoda fabryczna i wstrzykiwanie zależności, są nakładane na wierzch).
Tak więc, jeśli mielibyśmy zrobić funkcję zastępowania dla statyki bez zmiany czegokolwiek innego, mielibyśmy trudności z zamówieniem przesłonięć. Trudno byłoby zdefiniować ograniczony kontekst dla zastosowania przesłonięcia, więc można byłoby przesłonić globalnie, a nie lokalnie, jak w przypadku obiektów. Nie ma obiektu instancji, który mógłby zmienić zachowanie. Więc jeśli ktoś wywołał metodę statyczną, która została zastąpiona przez inną klasę, to czy zastąpienie powinno uzyskać kontrolę, czy nie? Jeśli istnieje wiele takich zastąpień, kto pierwszy przejmie kontrolę? druga? W przypadku zastąpienia obiektu instancji wszystkie te pytania mają sensowne i dobrze uzasadnione odpowiedzi, ale nie mają ich w przypadku statyki.
Zastąpienia statyki byłyby zasadniczo chaotyczne i takie rzeczy były już wcześniej robione.
Na przykład Mac OS System 7 i wcześniej korzystały z mechanizmu łatania pułapek w celu rozszerzenia systemu poprzez uzyskanie kontroli nad wywołaniami systemowymi wykonywanymi przez aplikację przed systemem operacyjnym. Można by pomyśleć o systemowej tablicy łatek wywołań systemowych jako tablicy wskaźników funkcji, podobnie jak na przykład vtable dla obiektów, z tym wyjątkiem, że była to pojedyncza tabela globalna.
Spowodowało to nieopisany smutek dla programistów z powodu nieuporządkowanej natury łatania pułapek. Ktokolwiek mógł załatać pułapkę, po prostu wygrał, nawet jeśli nie chciał. Każda łata pułapki przechwytywałaby poprzednią wartość pułapki dla pewnego rodzaju możliwości wywołania rodzica, co było wyjątkowo delikatne. Usunięcie łaty pułapkowej, powiedzmy, że kiedy nie musisz już wiedzieć o wywołaniu systemowym, uznano ją za złą formę, ponieważ tak naprawdę nie posiadałeś informacji potrzebnych do usunięcia łatki (gdybyś to zrobił, cofnąłbyś również wszelkie inne łaty, które pojawiły się później ty).
Nie oznacza to, że niemożliwe byłoby stworzenie mechanizmu zastępowania statyki, ale prawdopodobnie wolałbym zamiast tego zmienić pola statyczne i metody statyczne w pola instancji i metody instancji metaklas, tak aby normalny obiekt Zastosowanie miałyby wówczas techniki orientacji. Zauważ, że istnieją również systemy, które to robią: CSE 341: klasy i metaklasy Smalltalk ; Zobacz także: Co to jest odpowiednik Smalltalk w statyce Java?
Próbuję powiedzieć, że musiałbyś zrobić poważny projekt funkcji językowych, aby działał nawet w miarę dobrze. Na przykład zastosowano podejście naiwne, utykało, ale było bardzo problematyczne i prawdopodobnie (tj. Argumentowałbym) architektonicznie wadliwe, zapewniając niepełną i trudną do użycia abstrakcję.
Zanim skończysz projektować funkcję przesłonięć statycznych tak, aby działała dobrze, być może wymyśliłeś jakąś formę metaklasy, która jest naturalnym rozszerzeniem OOP na metody klasowe. Nie ma więc powodu, aby tego nie robić - a niektóre języki faktycznie tak robią. Być może jest to tylko trochę dodatkowy wymóg, że wiele języków decyduje się tego nie robić.
źródło
this.instanceMethod()
ma dynamiczną rozdzielczość, więc jeśliself.staticMethod()
ma taką samą rozdzielczość, a mianowicie dynamiczną, nie byłaby to już metoda statyczna.Przesłanianie zależy od wirtualnej wysyłki: używasz typu środowiska wykonawczego
this
parametru, aby zdecydować, którą metodę wywołać. Metoda statyczna nie mathis
parametru, więc nie ma nic do wysłania.Niektóre języki, zwłaszcza Delphi i Python, mają zakres „pośredni”, który pozwala na to: metody klasowe. Metoda klasowa nie jest zwykłą metodą instancji, ale nie jest też statyczna; otrzymuje
self
parametr (zabawnie, oba języki nazywają gothis
parametremself
), który jest odniesieniem do samego typu obiektu, a nie do instancji tego typu. Dzięki tej wartości masz teraz typ do wirtualnej wysyłki.Niestety ani JVM, ani CLR nie ma nic porównywalnego.
źródło
self
których klasy są rzeczywistymi obiektami tworzonymi za pomocą instancji z nadpisywalnymi metodami - oczywiście Smalltalk, Ruby, Dart, Objective C, Self, Python? W porównaniu z językami używanymi po C ++, gdzie klasy nie są obiektami pierwszej klasy, nawet jeśli istnieje pewien dostęp do refleksji?virtual
a następnie zastąpić w klasie potomnej, podobnie jak metody instancji.Ty pytasz
pytam
Niektóre języki zmuszają cię do rozpoczęcia pokazu w sposób statyczny. Ale potem naprawdę możesz rozwiązać wiele problemów bez żadnych statycznych metod.
Niektóre osoby lubią stosować metody statyczne, gdy nie ma zależności od stanu w obiekcie. Niektórzy ludzie lubią stosować metody statyczne do budowy innych obiektów. Niektórzy ludzie lubią unikać metod statycznych w jak największym stopniu.
Żadna z tych osób nie ma racji.
Jeśli potrzebujesz zastąpić go, po prostu przestań oznaczać go statycznie. Nic się nie zepsuje, bo latają wokół ciebie bezpaństwowce.
źródło
_start()
Symbol w systemie Linux). W tym przykładzie plik wykonywalny jest obiektem (ma własną „tabelę wysyłki” i wszystko), a punktem wejścia jest operacja wywoływana dynamicznie. W związku z tym punkt wejścia programu jest z natury wirtualny, gdy jest oglądany z zewnątrz, i można łatwo sprawić, że będzie wyglądał wirtualny, również patrząc od wewnątrz.To nie jest kwestia „powinna”.
„Przesłanianie” oznacza „wysyłanie dynamiczne ”. „Metoda statyczna” oznacza „wysyłkę statyczną”. Jeśli coś jest statyczne, nie można go zastąpić. Jeśli coś można zastąpić, nie jest statyczne.
Twoje pytanie jest raczej podobne do pytania: „Dlaczego trójkołowce nie powinny mieć czterech kół?” Definicja z „motocykl” jest to, że ma trzy koła. Jeśli jest to trójkołowy, nie może mieć czterech kół, jeśli ma cztery koła, nie może być trójkołowy. Podobnie definicja „metody statycznej” polega na tym, że jest ona wysyłana statycznie. Jeśli jest to metoda statyczna, nie może być dynamicznie wysłana, jeśli może być dynamicznie wysłana, nie może być metodą statyczną.
Oczywiście możliwe jest zastosowanie metod klas, które można zastąpić. Lub możesz mieć język taki jak Ruby, w którym klasy są obiektami tak jak każdy inny obiekt, a zatem mogą mieć metody instancji, co całkowicie eliminuje potrzebę metod klasowych. (Ruby ma tylko jeden rodzaj metod: metody instancji. Nie ma metod klas, metod statycznych, konstruktorów, funkcji ani procedur.)
źródło
W języku C # zawsze wywołujesz członków statycznych za pomocą klasy, np .
BaseClass.StaticMethod()
NiebaseObject.StaticMethod()
. Więc w końcu, jeśliChildClass
dziedziczyszBaseClass
ichildObject
wystąpienieChildClass
, nie będziesz w stanie wywołać metody statycznejchildObject
. Zawsze będziesz musiał jawnie użyć prawdziwej klasy, więc postatic virtual
prostu nie ma sensu.Możesz na nowo zdefiniować tę samą
static
metodę w klasie podrzędnej i użyćnew
słowa kluczowego.Gdyby można było zadzwonić
baseObject.StaticMethod()
, twoje pytanie miałoby sens.źródło