É possível em C ++ ter uma função de membro que seja static
e virtual
? Aparentemente, não há uma maneira direta de fazer isso ( static virtual member();
é um erro de compilação), mas há pelo menos uma maneira de obter o mesmo efeito?
IE:
struct Object
{
struct TypeInformation;
static virtual const TypeInformation &GetTypeInformation() const;
};
struct SomeObject : public Object
{
static virtual const TypeInformation &GetTypeInformation() const;
};
Faz sentido usar GetTypeInformation()
tanto em uma instância ( object->GetTypeInformation()
) quanto em uma classe ( SomeObject::GetTypeInformation()
), que podem ser úteis para comparações e vitais para modelos.
As únicas maneiras em que consigo pensar envolvem escrever duas funções / uma função e uma constante, por classe, ou usar macros.
Alguma outra solução?
const
assinatura em um método sinaliza othis
ponteiro implícito como constante e não pode ser aplicado a métodos estáticos, pois não possuem o parâmetro implícito.Respostas:
Não, não há como fazê-lo, pois o que aconteceria quando você ligasse
Object::GetTypeInformation()
? Ele não pode saber qual versão de classe derivada chamar, pois não há nenhum objeto associado a ela.Você precisará torná-la uma função virtual não estática para funcionar corretamente; se você também quiser chamar a versão de uma classe derivada específica praticamente sem uma instância de objeto, precisará fornecer também uma segunda versão não virtual estática redundante.
fonte
Muitos dizem que não é possível, eu daria um passo adiante e diria que não tem sentido.
Um membro estático é algo que não se relaciona a nenhuma instância, apenas à classe.
Um membro virtual é algo que não se relaciona diretamente a nenhuma classe, apenas a uma instância.
Portanto, um membro virtual estático seria algo que não se relaciona a nenhuma instância ou classe.
fonte
static virtual
método, mas um métodostatic
purovirtual
é muito significativo em uma interface.static const string MyClassSillyAdditionalName
.Encontrei esse problema outro dia: eu tinha algumas classes cheias de métodos estáticos, mas queria usar herança e métodos virtuais e reduzir a repetição de código. Minha solução foi:
Em vez de usar métodos estáticos, use um singleton com métodos virtuais.
Em outras palavras, cada classe deve conter um método estático que você chama para obter um ponteiro para uma única instância compartilhada da classe. Você pode tornar os verdadeiros construtores privados ou protegidos, para que o código externo não possa usá-lo incorretamente, criando instâncias adicionais.
Na prática, usar um singleton é muito parecido com o uso de métodos estáticos, exceto que você pode tirar proveito dos métodos virtuais e de herança.
fonte
É possível!
Mas o que exatamente é possível, vamos diminuir. As pessoas geralmente desejam algum tipo de "função virtual estática" devido à duplicação de código necessária para poder chamar a mesma função através da chamada estática "SomeDerivedClass :: myfunction ()" e da chamada polimórfica "base_class_pointer-> myfunction ()". O método "Legal" para permitir essa funcionalidade é a duplicação de definições de função:
E se a classe base tiver um grande número de funções estáticas e a classe derivada tiver que substituir todas elas e esquecermos de fornecer uma definição duplicada para a função virtual. Certo, obteremos algum erro estranho durante o tempo de execução, o que é difícil de rastrear. Causa duplicação de código é uma coisa ruim. O seguinte tenta resolver este problema (e quero dizer de antemão que é completamente seguro para o tipo e não contém nenhuma magia negra como a do typeid ou do dynamic_cast :)
Portanto, queremos fornecer apenas uma definição de getTypeInformation () por classe derivada e é óbvio que deve ser uma definição de staticfunção porque não é possível chamar "SomeDerivedClass :: getTypeInformation ()" se getTypeInformation () for virtual. Como podemos chamar a função estática da classe derivada através do ponteiro para a classe base? Não é possível com o vtable porque o vtable armazena ponteiros apenas para funções virtuais e, como decidimos não usar funções virtuais, não podemos modificar o vtable para nosso benefício. Então, para poder acessar a função estática da classe derivada através do ponteiro para a classe base, precisamos armazenar de alguma forma o tipo de um objeto dentro de sua classe base. Uma abordagem é tornar a classe base modelada usando "padrão de modelo curiosamente recorrente", mas não é apropriado aqui e usaremos uma técnica chamada "apagamento de tipo":
Agora podemos armazenar o tipo de um objeto na classe base "Object" com uma variável "keeper":
Em uma classe derivada, o detentor deve ser inicializado durante a construção:
Vamos adicionar açúcar sintático:
Agora as declarações dos descendentes se parecem com:
uso:
Vantagens:
Desvantagens:
Questões em aberto:
1) existem nomes diferentes para funções estáticas e virtuais como resolver a ambiguidade aqui?
2) como chamar implicitamente OVERRIDE_STATIC_FUNCTIONS dentro de cada construtor?
fonte
Embora Alsk já tenha dado uma resposta bastante detalhada, gostaria de adicionar uma alternativa, pois acho que sua implementação aprimorada é complicada demais.
Começamos com uma classe base abstrata, que fornece a interface para todos os tipos de objetos:
Agora precisamos de uma implementação real. Mas, para evitar a necessidade de escrever os métodos estático e virtual, teremos nossas classes de objetos reais herdadas dos métodos virtuais. Obviamente, isso só funciona se a classe base souber acessar a função de membro estático. Portanto, precisamos usar um modelo e passar o nome real da classe de objetos para ele:
Finalmente, precisamos implementar nossos objetos reais. Aqui, apenas precisamos implementar a função de membro estático, as funções de membro virtual serão herdadas da classe de modelo ObjectImpl, instanciadas com o nome da classe derivada, para acessar seus membros estáticos.
Vamos adicionar um código para testar:
Adendo (12 de janeiro de 2019):
Em vez de usar a função GetClassNameStatic (), você também pode definir o nome da classe como um membro estático, até mesmo "inline", que o IIRC funciona desde o C ++ 11 (não se assuste com todos os modificadores :)):
fonte
É possível. Faça duas funções: estática e virtual
fonte
Não, isso não é possível, porque as funções de membro estático não possuem um
this
ponteiro. E membros estáticos (funções e variáveis) não são realmente membros da classe em si. Eles são invocadosClassName::member
e aderem aos especificadores de acesso à classe. O armazenamento deles é definido em algum lugar fora da classe; o armazenamento não é criado sempre que você instancia um objeto da classe. Os ponteiros para os alunos são especiais em semântica e sintaxe. Um ponteiro para um membro estático é um ponteiro normal em todos os aspectos.funções virtuais em uma classe precisam do
this
ponteiro e são muito acopladas à classe, portanto, elas não podem ser estáticas.fonte
this
ponteiro. funções estáticas não são específicas para uma instância e não precisariam dela. Portanto, não é por isso que os membros estáticos virtuais são impossíveis.Bem, uma resposta bastante tardia, mas é possível usar o padrão curiosamente recorrente do modelo. Este artigo da wikipedia tem as informações de que você precisa e também o exemplo sob polimorfismo estático.
fonte
Eu acho que o que você está tentando fazer pode ser feito através de modelos. Estou tentando ler nas entrelinhas aqui. O que você está tentando fazer é chamar um método a partir de algum código, onde ele chama uma versão derivada, mas o chamador não especifica qual classe. Exemplo:
Você deseja que Try () chame a versão Bar de M sem especificar Bar. A maneira como você faz isso para estática é usar um modelo. Então mude assim:
fonte
Não, a função de membro estático não pode ser virtual. Já que o conceito virtual é resolvido em tempo de execução com a ajuda do vptr, e o vptr não é membro estático de uma classe. Devido a essa função de membro estático não pode acessar o vptr, o membro estático pode seja virtual.
fonte
Não é possível, mas isso é apenas por uma omissão. Não é algo que "não faz sentido", como muitas pessoas parecem afirmar. Para ser claro, eu estou falando sobre algo como isto:
Isso é 100% algo que poderia ser implementado (apenas não foi) e eu argumentaria algo que é útil.
Considere como as funções virtuais normais funcionam. Remova os se
static
adicione outros itens e temos:Isso funciona bem e, basicamente, o que acontece é que o compilador cria duas tabelas, chamadas VTables, e atribui índices às funções virtuais como esta
A seguir, cada classe com funções virtuais é aumentada com outro campo que aponta para sua VTable, portanto, o compilador basicamente as altera para ficar assim:
Então o que realmente acontece quando você liga
b->sayMyName()
? Basicamente isso:(O primeiro parâmetro se torna
this
.)Tudo bem, então como ele funcionaria com funções virtuais estáticas? Bem, qual é a diferença entre funções membro estáticas e não estáticas? A única diferença é que os últimos recebem um
this
ponteiro.Podemos fazer exatamente o mesmo com funções virtuais estáticas - basta remover o
this
ponteiro.Isso poderia suportar as duas sintaxes:
Portanto, ignore todos os opositores. Ele faz sentido. Por que não é suportado então? Eu acho que é porque tem muito pouco benefício e pode até ser um pouco confuso.
A única vantagem técnica sobre uma função virtual normal é que você não precisa passar
this
para a função, mas não acho que isso faria alguma diferença mensurável no desempenho.Isso significa que você não tem uma função estática e não estática separada para casos em que você tem uma instância e quando você não tem uma instância, mas também pode ser confuso que seja realmente "virtual" quando você usa a chamada da instância.
fonte
Não, não é possível, pois os membros estáticos são vinculados em tempo de compilação, enquanto os membros virtuais são vinculados em tempo de execução.
fonte
Primeiro, as respostas estão corretas: o que o OP está solicitando é uma contradição em termos: métodos virtuais dependem do tipo de tempo de execução de uma instância; funções estáticas especificamente não dependem de uma instância - apenas de um tipo. Dito isto, faz sentido ter funções estáticas retornando algo específico a um tipo. Por exemplo, eu tinha uma família de classes MouseTool para o padrão State e comecei a ter cada uma delas uma função estática retornando o modificador de teclado que a acompanhava; Usei essas funções estáticas na função de fábrica que criaram a instância correta do MouseTool. Essa função verificou o estado do mouse em relação a MouseToolA :: keyboardModifier (), MouseToolB :: keyboardModifier (), etc. e, em seguida, instancia o apropriado. É claro que mais tarde eu queria verificar se o estado estava certo, então eu queria escrever algo como "
Portanto, se você estiver querendo isso, talvez queira refazer sua solução. Ainda assim, entendo o desejo de ter métodos estáticos e os chamo dinamicamente com base no tipo dinâmico de uma instância. Eu acho que o padrão de visitantes pode dar o que você deseja. Dá o que você quer. É um pouco de código extra, mas pode ser útil para outros visitantes.
Veja: http://en.wikipedia.org/wiki/Visitor_pattern para obter mais informações.
Então, para cada objeto concreto:
e defina o visitante base:
Em seguida, o visitante concreto que seleciona a função estática apropriada:
finalmente, use-o:
Notas:
Se você deseja evitar erros de copiar e colar, em que um dos métodos de visita chama a função estática incorreta, você pode usar uma função auxiliar de modelo (que não pode ser virtual) para o visitante com um modelo como este:
fonte
Foo foo; ... foo::bar();
vez deFoo::bar();
). Isso não é diferente,decltype(foo)::bar();
mas isso seria estatisticamente vinculado. A abordagem do visitante parece uma maneira razoável de obter esse comportamento sem tornar o método estático um método const virtual.Com o c ++, você pode usar herança estática com o método crt. Por exemplo, é amplamente utilizado no modelo de janela atl & wtl.
Consulte https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Para ser simples, você tem uma classe que é modelada por si mesma, como myclass de classe: public myancestor. A partir deste ponto, a classe myancestor agora pode chamar sua função estática T :: YourImpl.
fonte
Talvez você possa tentar minha solução abaixo:
fonte
Base::mSelf
refere-se à instância MAIS RECENTEMENTE construída de qualquer classe derivada, mesmo que essa instância tenha sido destruída . Então, oclass D1 : public Base ...; class D2 : public Base ...; ...; D1* pd1 = new D1(); D2* pd2 = new D2(); pd1->MyStaticFun(); /* calls D2::MyVirtualFun() */ delete pd2; pd1->MyStaticFun(); /* calls via deleted pd2 */
que NÃO é o que se deseja.Como outros já disseram, existem duas informações importantes:
this
ponteiro ao fazer uma chamada de função estática ethis
ponteiro aponta para a estrutura em que a tabela virtual, ou thunk, é usada para procurar qual método de tempo de execução chamar.Uma função estática é determinada em tempo de compilação.
Eu mostrei este exemplo de código nos membros estáticos do C ++ na classe ; mostra que você pode chamar um método estático, dado um ponteiro nulo:
fonte
p < null
,p >= null
etc , todos são indefinidos também # #