Информация об изменениях

Сообщение Re[12]: Книжка по UB от 13.08.2025 14:54

Изменено 13.08.2025 14:58 so5team

Re[12]: Книжка по UB
Здравствуйте, watchmaker, Вы писали:

W>Тогда, если быть последовательным, придётся принять утверждение: "в final-классах виртуальная диспетчеризация не работает". Как думаешь, хорошее и полезное это утверждение, чтобы его запоминать?


Тут требуется пояснительная бригада ибо аппеляцию к final-классам не понял от слова совсем.

Я выше дал определение для виртуальности: "виртуальность в том и состоит, что мы дергаем метод через указатель/ссылку на базовый класс, а получаем вызов кода из производного класса"

Берем пример:
#include <iostream>

class base
{
    
public:
    base() {
        std::cout << "base {" << std::endl;
        f();
        std::cout << "base }" << std::endl;
    }
    
    virtual void f() { std::cout << "base::f" << std::endl; }
};

void call(base & b) { b.f(); }

class derived : public base
{
    void f() override { std::cout << "derived::f" << std::endl; }
    
public:
    derived() = default;
};

class another_derived final : public base
{
    void f() override { std::cout << "another_derived::f" << std::endl; }
    
public:
    another_derived() = default;
};

int main()
{
    derived d;
    another_derived ad; 
    
    std::cout << "---" << std::endl;
    
    call(d);
    call(ad);
}

цынк

И видим внутри call то, о чем я пишу: по ссылке на базовый класс вызывается f(). При этом по факту вызвается f из наследника. Вне зависимости от final или не-final.

Тогда как в конструкторе base у нас this указывает на base, по this вызывается f(), но это не f() из наследников.

Т.е. в данном случае виртуальности у вызова нет. ЧТД.
Re[12]: Книжка по UB
Здравствуйте, watchmaker, Вы писали:

W>Тогда, если быть последовательным, придётся принять утверждение: "в final-классах виртуальная диспетчеризация не работает". Как думаешь, хорошее и полезное это утверждение, чтобы его запоминать?


Тут требуется пояснительная бригада ибо аппеляцию к final-классам не понял от слова совсем.

Я выше дал определение для виртуальности: "виртуальность в том и состоит, что мы дергаем метод через указатель/ссылку на базовый класс, а получаем вызов кода из производного класса"

Берем пример:
#include <iostream>

class base
{
    
public:
    base() {
        std::cout << "base {" << std::endl;
        f();
        std::cout << "base }" << std::endl;
    }
    
    virtual void f() { std::cout << "base::f" << std::endl; }
};

void call(base & b) { b.f(); }

class derived : public base
{
    void f() override { std::cout << "derived::f" << std::endl; }
    
public:
    derived() = default;
};

class another_derived final : public base
{
    void f() override { std::cout << "another_derived::f" << std::endl; }
    
public:
    another_derived() = default;
};

int main()
{
    derived d;
    another_derived ad; 
    
    std::cout << "---" << std::endl;
    
    call(d);
    call(ad);
}

цынк

И видим внутри call то, о чем я пишу: по ссылке на базовый класс вызывается f(). При этом по факту вызвается f из наследника. Вне зависимости от final или не-final.

Тогда как в конструкторе base у нас this указывает на base, по this вызывается f(), но это не f() из наследников.

Т.е. в данном случае (т.е. внутри конструктора) виртуальности у вызова нет. ЧТД.