Рассмотрим такой фрагмент кода:

[-]
View Code C++
#include <iostream>

struct A {
    A() {};
    ~A() { ::std::cout << "A::~A()\n"; }
};

struct B : public A {
    B() {};
    ~B() { ::std::cout << "B::~B()\n"; }
};

int main(void)
{
    {
        const A& a = B();
    }

    return 0;
}

Вопрос: что будет выведено в результате выполнения кода?

Правильный ответ:

[-]
View Code Text
B::~B()
A::~A()

Почему? Стандарт языка C++ указывает, что привязка временного объекта к константной ссылке увеличивает время жизни объекта до времени жизни константной ссылки.

Из кода нельзя убрать const, потому что в присваивании вызов конструктора возвращает, по сути дела, временный объект (rvalue в терминологии стандарта), а привязывать к неконстантным ссылкам можно только lvalue.

Есть маленький нюанс: вышесказанное не применимо к членам класса:

[-]
View Code C++
#include <iostream>
#include <string>

struct A {
    A(void) { ::std::cout << "A::A()\n"; };
    ~A() { ::std::cout << "A::~A()\n"; }
};

struct B {
    const A& a;
    B(const A& ra) : a(ra) {};
    ~B() { ::std::cout << a.s << "\nB::~B()\n"; }
};

int main(void)
{
    B b(A("test"));
    return 0;
}

Деструктор A::~A() будет вызван после выполнения конструктора B::B(), это надо иметь в виду.

В случае, когда ссылка покидает пределы видимости, компилятор вызовет тот же деструктор, что и для временного объекта (на который эта ссылка ссылается). В результате мы получаем вызов правильного деструктора без виртуальных функций и расходов, с ними связанных.

Тем не менее, настоящим полиморфизмом это назвать нельзя. Рассмотрим пример:

[-]
View Code C++
#include <iostream>

struct A {
    A() {};
    ~A() { ::std::cout << "A::~A()\n"; }
    void test(void) const { ::std::cout << "A::test()\n"; }
};

struct B : public A {
    B() {};
    ~B() { ::std::cout << "B::~B()\n"; }
    void test(void) const { ::std::cout << "B::test()\n"; }
};

int main(void)
{
    const A& a = B();
    a.test();

    return 0;
}

Метод test просто обязан быть константным, ибо при использовании константной ссылки мы имеем дело с константным объектом.
Такой код выдаст следующий результат:

[-]
View Code Text
A::test()
B::~B()
A::~A()

Как видим, полноценного полиморфизма не получается.

Всё же интересно, какое применение данному подходу можно найти?

Добавить в закладки

Связанные записи

29
Апр
2009

Комментарии к статье «Полиморфизм времени компиляции без использования виртуальных функций»  »

К статье «Полиморфизм времени компиляции без использования виртуальных функций» комментариев пока нет. Не хотите ли стать первым?

Подписаться на RSS-ленту комментариев к статье «Полиморфизм времени компиляции без использования виртуальных функций» Trackback URL: http://blog.sjinks.org.ua/c-cpp/551-compile-time-polymorphism-without-virtual-functions/trackback/

Оставить комментарий к записи «Полиморфизм времени компиляции без использования виртуальных функций»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя