Nie jest to możliwe, ale to tylko z powodu zaniedbania. To nie jest coś, co „nie ma sensu”, jak twierdzi wielu ludzi. Żeby było jasne, mówię o czymś takim:
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.
}
Jest to w 100% coś, co można zaimplementować (po prostu nie ma) i argumentowałbym, że jest to przydatne.
Zastanów się, jak działają normalne funkcje wirtualne. Usuń static
s i dodaj kilka innych rzeczy i mamy:
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();
}
Działa to dobrze iw zasadzie kompilator tworzy dwie tabele zwane tabelami VTables i przypisuje indeksy do takich funkcji wirtualnych
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
};
Następnie każda klasa z funkcjami wirtualnymi jest rozszerzana o inne pole wskazujące na jej VTable, więc kompilator zasadniczo zmienia je tak, aby wyglądały następująco:
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";
}
};
Więc co się właściwie dzieje, kiedy dzwonisz b->sayMyName()
? Zasadniczo to:
b->vtable[Base_Virtual_Functions::sayMyName](b);
(Pierwszy parametr zmieni się na this
.)
Dobrze, więc jak by to działało ze statycznymi funkcjami wirtualnymi? Jaka jest różnica między statycznymi i niestatycznymi funkcjami składowymi? Jedyną różnicą jest to, że te ostatnie otrzymują this
wskaźnik.
Dokładnie to samo możemy zrobić ze statycznymi funkcjami wirtualnymi - wystarczy usunąć this
wskaźnik.
b->vtable[Base_Virtual_Functions::sayMyName]();
To mogłoby wtedy obsługiwać obie składnie:
b->sayMyName(); // Prints "Base" or "Derived"...
Base::sayMyName(); // Always prints "Base".
Więc zignoruj wszystkich przeciwników. To ma sens. Dlaczego więc nie jest obsługiwany? Myślę, że to dlatego, że ma bardzo małe korzyści, a nawet może być trochę zagmatwane.
Jedyną przewagą techniczną w porównaniu ze zwykłą funkcją wirtualną jest to, że nie trzeba przechodzić this
do funkcji, ale nie sądzę, aby miało to jakikolwiek wymierny wpływ na wydajność.
Oznacza to, że nie masz oddzielnej funkcji statycznej i niestatycznej w przypadkach, gdy masz instancję i nie masz instancji, ale może być również mylące, że jest ona naprawdę „wirtualna” tylko wtedy, gdy używasz wywołanie instancji.
const
sygnatura metody in a oznacza niejawnythis
wskaźnik jako stały i nie może być stosowana do metod statycznych, ponieważ nie mają one niejawnego parametru.