четверг, 14 августа 2025 г.

[prog.c++] dynamic_cast и непубличные базовые классы

Всю свою профессиональную жизнь по мере необходимости пользовался dynamic_cast-ом в C++ и не знал, что dynamic_cast не будет делать приведение к ссылке/указателю на непубличный базовый класс.

Вот пример:

#include <iostream>

class iface {
public:
    virtual ~iface() = default;

    virtual void f() = 0;
};

class basic_impl {
public:
    virtual ~basic_impl() = default;

    void impl_f() {}
};

class first_derived final : public iface, protected basic_impl
{
public:
    void f() override { impl_f(); }
};

class second_derived final : public iface, public basic_impl
{
public:
    void f() override { impl_f(); }
};

void try_dynamic_cast(iface * base)
{
    std::cout << "trying to cast " << typeid(*base).name() << std::flush;
    if(auto * p = dynamic_cast<basic_impl *>(base); p)
        std::cout << "... OK" << std::endl;
    else
        std::cout << "... FAILURE" << std::endl;
}

int main() {
    first_derived f;
    second_derived s;

    try_dynamic_cast(&f);
    try_dynamic_cast(&s);
}

Обращаю внимание, что для first_derived класс basic_impl -- это protected-база.

В результате его запуска получим:

trying to cast 13first_derived... FAILURE
trying to cast 14second_derived... OK

Цынк.

PS. Вот так: век живи, век учись. А помрешь все равно дураком 🙂

1 комментарий:

nshmakov комментирует...

Что в целом выглядит логично: публичный интерфейс basic_impl должен же стать protected у наследника