Em respostas a essa pergunta, o consenso geral era que métodos estáticos não deveriam ser substituídos (e, portanto, funções estáticas em C # não podem ser virtuais ou abstratas). Este não é apenas o caso em C #; O Java também proíbe isso e o C ++ também não parece gostar. No entanto, posso pensar em muitos exemplos de funções estáticas que gostaria de substituir em uma classe filho (por exemplo, métodos de fábrica). Enquanto, em teoria, existem maneiras de contorná-las, nenhuma delas é limpa ou simples.
Por que as funções estáticas não devem ser substituíveis?
object-oriented-design
abstract-class
static-methods
PixelArtDragon
fonte
fonte
self
ponteiro que aponta para a classe e não para uma instância da classe.Respostas:
Com os métodos estáticos, não há objeto para fornecer o controle adequado do mecanismo de substituição.
O mecanismo normal do método virtual de classe / instância permite o controle preciso de substituições da seguinte maneira: cada objeto real é uma instância de exatamente uma classe. Essa classe determina o comportamento das substituições; sempre obtém o primeiro acesso aos métodos virtuais. Em seguida, ele pode optar por chamar o método pai no momento certo para sua implementação. Cada método pai também recebe sua vez de chamar seu método pai. Isso resulta em uma bela cascata de invocações pai, que realiza uma das noções de reutilização de código pelas quais a orientação a objetos é conhecida. (Aqui o código das classes base / superclasses está sendo reutilizado de uma maneira relativamente complexa; outra noção ortogonal de reutilização de código no OOP é simplesmente ter vários objetos da mesma classe.)
As classes base podem ser reutilizadas por várias subclasses e cada uma pode coexistir confortavelmente. Cada classe usada para instanciar objetos ditando seu próprio comportamento, coexistindo pacificamente e simultaneamente com as outras. O cliente tem controle sobre quais comportamentos deseja e quando, escolhendo qual classe usar para instanciar um objeto e repassar para outras pessoas, conforme desejado.
(Este não é um mecanismo perfeito, pois sempre é possível identificar recursos que não são suportados, é por isso que é por isso que padrões como o método de fábrica e a injeção de dependência são colocados em camadas)
Portanto, se tivéssemos um recurso de substituição de estática sem alterar mais nada, teríamos dificuldade em ordenar as substituições. Seria difícil definir um contexto limitado para a aplicabilidade da substituição, portanto, você obteria a substituição globalmente, e não localmente, como nos objetos. Não há objeto de instância para alterar o comportamento. Portanto, se alguém invocou o método estático que foi substituído por outra classe, a substituição deve ter controle ou não? Se houver várias substituições, quem obtém o controle primeiro? segundo? Com a substituição de objetos de instância, todas essas perguntas têm respostas significativas e bem fundamentadas, mas com estática elas não.
Substituições de estática seriam substancialmente caóticas e, coisas como essa já foram feitas antes.
Por exemplo, o Mac OS System 7 e versões anteriores usavam um mecanismo de correção de traps para estender o sistema, obtendo o controle das chamadas do sistema feitas pelo aplicativo antes do sistema operacional. Você poderia pensar em tabela de correção a chamada de sistema como uma matriz de ponteiros de função, bem como uma vtable para objetos de instância, exceto que ele era uma única tabela global.
Isso causou um sofrimento incalculável para os programadores, devido à natureza não ordenada da correção de armadilhas. Quem conseguiu consertar a armadilha venceu basicamente, mesmo que não quisesse. Cada corretor da armadilha capturaria o valor anterior da armadilha para um tipo de recurso de chamada pai, que era extremamente frágil. A remoção de um patch de interceptação, digamos que, quando você não precisava mais saber sobre uma chamada de sistema, era considerada péssima, porque na verdade não tinha as informações necessárias para remover o patch (se o fizesse, também desataria outros patches que se seguiram). você).
Isso não quer dizer que seria impossível criar um mecanismo para substituições de estática, mas o que eu provavelmente preferiria fazer é transformar os campos estáticos e métodos estáticos em campos de instâncias e métodos de metaclasses, para que o objeto normal técnicas de orientação seriam aplicadas. Observe que existem sistemas que fazem isso também: CSE 341: Classes e metaclasses de Smalltalk ; Veja também: Qual é o equivalente do Smalltalk à estática do Java?
Estou tentando dizer que você precisaria criar um design sério de recurso de linguagem para fazê-lo funcionar razoavelmente bem. Por exemplo, uma abordagem ingênua foi feita, mancou, mas era muito problemática e, sem dúvida (eu diria), com falhas arquiteturais, fornecendo uma abstração incompleta e difícil de usar.
Quando você terminar de projetar o recurso de substituições estáticas para funcionar bem, você poderá ter inventado alguma forma de metaclasses, que é uma extensão natural do OOP para / para métodos baseados em classes. Portanto, não há razão para não fazer isso - e alguns idiomas realmente fazem. Talvez seja apenas um requisito adicional que vários idiomas optem por não fazer.
fonte
this.instanceMethod()
tem resolução dinâmica, por isso, seself.staticMethod()
tiver a mesma resolução, ou seja, dinâmica, não seria mais um método estático.A substituição depende do envio virtual: você usa o tipo de tempo de execução do
this
parâmetro para decidir qual método chamar. Um método estático não temthis
parâmetro, portanto não há nada para despachar.Algumas linguagens, especialmente Delphi e Python, têm um escopo "intermediário" que permite isso: métodos de classe. Um método de classe não é um método de instância comum, mas também não é estático; ele recebe um
self
parâmetro (divertidamente, os dois idiomas chamam othis
parâmetroself
) que é uma referência ao tipo de objeto em si, e não a uma instância desse tipo. Com esse valor, agora você tem um tipo disponível para o envio virtual.Infelizmente, nem a JVM nem o CLR têm algo comparável.
fonte
self
que possuem classes como objetos instanciados reais com métodos substituíveis - Smalltalk, é claro, Ruby, Dart, Objective C, Self, Python? Comparado com as linguagens usadas após o C ++, onde as classes não são objetos de primeira classe, mesmo que haja algum acesso à reflexão?virtual
e substituído em uma classe descendente, assim como os métodos de instância.Você pergunta
eu pergunto
Certos idiomas forçam você a iniciar o show de forma estática. Mas depois disso, você realmente pode resolver muitos problemas sem mais métodos estáticos.
Algumas pessoas gostam de usar métodos estáticos sempre que não há dependência de estado em um objeto. Algumas pessoas gostam de usar métodos estáticos para a construção de outros objetos. Algumas pessoas gostam de evitar métodos estáticos, tanto quanto possível.
Nenhuma dessas pessoas está errada.
Se você precisar que seja substituível, pare de rotulá-lo como estático. Nada vai quebrar porque você tem um objeto apátrida voando por aí.
fonte
_start()
símbolo no Linux). Nesse exemplo, o executável é o objeto (possui sua própria "tabela de despacho" e tudo) e o ponto de entrada é a operação despachada dinamicamente. Portanto, o ponto de entrada de um programa é inerentemente virtual quando visto de fora e pode ser facilmente visualizado quando visto de dentro também.Não é uma questão de "deveria".
"Substituir" significa "despachar dinamicamente ". "Método estático" significa "despachar estaticamente". Se algo é estático, não pode ser substituído. Se algo pode ser substituído, não é estático.
Sua pergunta é bastante semelhante à pergunta: "Por que os triciclos não deveriam ter quatro rodas?" A definição de "triciclo" é que tem três rodas. Se é um triciclo, não pode ter quatro rodas, se tem quatro rodas, não pode ser um triciclo. Da mesma forma, a definição de "método estático" é que ele é enviado estaticamente. Se é um método estático, não pode ser despachado dinamicamente, se pode ser despachado dinamicamente, não pode ser um método estático.
É claro que é perfeitamente possível ter métodos de classe que possam ser substituídos. Ou você pode ter uma linguagem como Ruby, onde classes são objetos como qualquer outro objeto e, portanto, podem ter métodos de instância, o que elimina completamente a necessidade de métodos de classe. (Ruby possui apenas um tipo de método: métodos de instância. Ele não possui métodos de classe, métodos estáticos, construtores, funções ou procedimentos.)
fonte
Em C #, você sempre chama membros estáticos usando a classe, por exemplo
BaseClass.StaticMethod()
, nãobaseObject.StaticMethod()
. Portanto, eventualmente, se vocêChildClass
herdou deBaseClass
echildObject
uma instância deChildClass
, não poderá chamar seu método estático dechildObject
. Você sempre precisará usar explicitamente a classe real, para questatic virtual
simplesmente não faça sentido.O que você pode fazer é redefinir o mesmo
static
método na sua classe filho e usar anew
palavra - chave.Se fosse possível ligar
baseObject.StaticMethod()
, sua pergunta faria sentido.fonte