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:
struct Base {
static virtual void sayMyName() {
cout << "Base\n";
}
};
struct Derived : public Base {
static void sayMyName() override {
cout << "Derived\n";
}
};
void foo(Base *b) {
b->sayMyName();
Derived::sayMyName(); // Also would work.
}
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:
struct Base {
virtual void sayMyName() {
cout << "Base\n";
}
virtual void foo() {
}
int somedata;
};
struct Derived : public Base {
void sayMyName() override {
cout << "Derived\n";
}
};
void foo(Base *b) {
b->sayMyName();
}
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
enum Base_Virtual_Functions {
sayMyName = 0;
foo = 1;
};
using VTable = void*[];
const VTable Base_VTable = {
&Base::sayMyName,
&Base::foo
};
const VTable Derived_VTable = {
&Derived::sayMyName,
&Base::foo
};
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:
struct Base {
VTable* vtable;
virtual void sayMyName() {
cout << "Base\n";
}
virtual void foo() {
}
int somedata;
};
struct Derived : public Base {
VTable* vtable;
void sayMyName() override {
cout << "Derived\n";
}
};
Então o que realmente acontece quando você liga b->sayMyName()
? Basicamente isso:
b->vtable[Base_Virtual_Functions::sayMyName](b);
(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.
b->vtable[Base_Virtual_Functions::sayMyName]();
Isso poderia suportar as duas sintaxes:
b->sayMyName(); // Prints "Base" or "Derived"...
Base::sayMyName(); // Always prints "Base".
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.
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.