Это невозможно, но это просто упущение. Это не то, что «не имеет смысла», как, кажется, утверждают многие люди. Для ясности, я говорю примерно о таком:
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();
}
Это на 100% то, что можно реализовать (а этого просто нет), и я бы сказал, что это полезно.
Рассмотрим, как работают обычные виртуальные функции. Удалите static
s и добавьте еще кое-что, и мы получим:
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();
}
Это работает нормально, и в основном происходит то, что компилятор создает две таблицы, называемые VTables, и назначает индексы виртуальным функциям, подобным этой.
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
};
Затем каждый класс с виртуальными функциями дополняется другим полем, указывающим на его VTable, поэтому компилятор в основном меняет их так:
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";
}
};
Тогда что на самом деле происходит, когда вы звоните b->sayMyName()
? В основном это:
b->vtable[Base_Virtual_Functions::sayMyName](b);
(Первый параметр становится this
.)
Хорошо, хорошо, как бы он работал со статическими виртуальными функциями? Ну, в чем разница между статическими и нестатическими функциями-членами? Единственное отличие в том, что последние получают this
указатель.
Мы можем сделать то же самое со статическими виртуальными функциями - просто удалите this
указатель.
b->vtable[Base_Virtual_Functions::sayMyName]();
Тогда это может поддерживать оба синтаксиса:
b->sayMyName();
Base::sayMyName();
Так что игнорируйте всех скептиков. В этом есть смысл. Почему тогда не поддерживается? Я думаю, это потому, что от этого мало пользы и может даже немного сбить с толку.
Единственное техническое преимущество по сравнению с обычной виртуальной функцией заключается в том, что вам не нужно переходить this
к функции, но я не думаю, что это окажет заметное влияние на производительность.
Это означает, что у вас нет отдельной статической и нестатической функции для случаев, когда у вас есть экземпляр, и когда у вас нет экземпляра, но также может сбивать с толку тот факт, что он действительно «виртуальный» только тогда, когда вы используете вызов экземпляра.
const
в сигнатуре метода помечается неявныйthis
указатель как константа, и он не может применяться к статическим методам, поскольку у них отсутствует неявный параметр.