Здравствуйте, rg45, Вы писали:
R>Так и как можно проверить, каким образом дёрнули метод?
А нам не важно как именно дернули -- через обращение к vtable или путем прямого вызова.
Нам важно какой метод в итоге был вызван. Т.е. конкретный механизм вызова всего лишь скучная деталь реализации.
S>>Именно это определение и нарушается, когда мы рассматриваем ситуацию с вызовом виртуальных методов в конструкторах/деструкторах. В С++.
R>Если не трудно, можно ещё раз указать пункт, который нарушается?
struct s1 {
virtual void f() { std::cout << "s1::f" << std::endl; }
s1() {
this->f(); // (1)
}
void call_f() {
this->f(); // (3)
}
};
struct s2 : public s1 {
void f() override { std::cout << "s2::f" << std::endl; }
};
int main() {
s2 s; // (2)
s.call_f(); // (4)
}
В точке (2) у нас конструируется объект типа s2, у которого должен быть собственный переопределенный f.
В точке (1) у нас на руках указатель на базовый тип s1 (это this через который идет вызов f).
Но в точке (1) вызов виртуального метода через указатель на базовый тип мы получаем не вызов s2::f, а вызов s1::f.
В точке (4) у нас все тот же объект типа s2.
Через вызов call_f мы приходим в точку (3), в которой у нас на руках опять указатель на базовый тип s1.
Однако, в точке (3) вызов виртуального метода через указатель на базовый тип мы получаем вызов s2::f, а не s1::f.
Тогда как в Java, Ruby или Python (подозреваю, что и в C#, и в D) мы в точках (1) и (3) получим одинаковое поведение.