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

Немного об использовании константных ссылок

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

[-]
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()

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

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

Автор: ; опубликовано в: C/C++; метки: C/C++, полиморфизм
29
Апр
2009

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

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

Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

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

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

गते गते पारगते पारसंगते बोधि स्वाहा