Це неможливо, але це лише тому, що упущення. Це не те, що "не має сенсу", як здається, багато людей. Щоб було зрозуміло, я говорю про щось подібне:
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.
}
Це на 100% те, що можна було б реалізувати (просто не було), і я заперечую щось корисне.
Поміркуйте, як працюють звичайні віртуальні функції. Видаліть static
і додайте ще деякі речі, і ми маємо:
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(); // Prints "Base" or "Derived"...
Base::sayMyName(); // Always prints "Base".
Тож ігноруйте всіх найсайєрів. Це має сенс. Чому його тоді не підтримували? Я думаю, це тому, що це має дуже мало користі і навіть може трохи заплутати.
Єдина технічна перевага перед звичайною віртуальною функцією полягає в тому, що вам не потрібно переходити this
до функції, але я не думаю, що це може змінити продуктивність.
Це означає, що ви не маєте окремої статичної та нестатичної функції для випадків, коли у вас є екземпляр, і коли у вас немає екземпляра, але також може бути заплутано те, що це дійсно "віртуально", коли ви використовуєте виклик екземпляра.
const
підпис в методі позначає неявнийthis
покажчик як постійний і не може бути застосований до статичних методів, оскільки у них відсутній неявний параметр.