No es posible, pero eso es solo por una omisión. No es algo que "no tenga sentido" como mucha gente parece reclamar. Para ser claros, estoy hablando de algo como esto:
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.
}
Esto es 100% algo que podría implementarse (simplemente no lo ha hecho), y diría que es algo útil.
Considere cómo funcionan las funciones virtuales normales. Elimine el static
sy agregue algunas otras cosas y tenemos:
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();
}
Esto funciona bien y, básicamente, lo que sucede es que el compilador crea dos tablas, llamadas VTables, y asigna índices a las funciones virtuales 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 continuación, cada clase con funciones virtuales se aumenta con otro campo que apunta a su VTable, por lo que el compilador básicamente las cambia para que sean así:
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";
}
};
Entonces, ¿qué sucede realmente cuando llamas b->sayMyName()
? Básicamente esto:
b->vtable[Base_Virtual_Functions::sayMyName](b);
(El primer parámetro se convierte this
).
Bien, ¿cómo funcionaría con funciones virtuales estáticas? ¿Cuál es la diferencia entre las funciones miembro estáticas y no estáticas? La única diferencia es que este último obtiene un this
puntero.
Podemos hacer exactamente lo mismo con funciones virtuales estáticas: simplemente quite el this
puntero.
b->vtable[Base_Virtual_Functions::sayMyName]();
Esto podría admitir ambas sintaxis:
b->sayMyName(); // Prints "Base" or "Derived"...
Base::sayMyName(); // Always prints "Base".
Así que ignora a todos los detractores. Se hace tiene sentido. ¿Por qué no es compatible entonces? Creo que es porque tiene muy pocos beneficios e incluso podría ser un poco confuso.
La única ventaja técnica sobre una función virtual normal es que no necesita pasar this
a la función, pero no creo que eso suponga una diferencia apreciable en el rendimiento.
Significa que no tiene una función estática y no estática separada para los casos en que tiene una instancia y cuando no tiene una instancia, pero también puede ser confuso que solo sea realmente "virtual" cuando usa la llamada de instancia
const
firma en un método marca elthis
puntero implícito como constante y no se puede aplicar a los métodos estáticos, ya que carecen del parámetro implícito.