2013-05-02 8 views
2

Рассмотрим следующий код (минимальная версия):C++ - базовая реализация, называемая ссылкой на производную?

#include <iostream> 

struct Base 
{ 
    virtual ~Base() {} 

    virtual void test() const { std::cout << "base"; } 
}; 

struct Derived : public Base 
{ 
    void test() const { std::cout << "derived"; } 
}; 

struct Composite 
{ 
    const Derived &ref; 

    Composite(const Derived &ref) : ref(ref) {} 

    void testRef() const { ref.test(); } 
}; 

int main() 
{ 
    Composite c((Derived())); 
    c.testRef(); 
} 

Это на самом деле производит 'базу' при использовании последней MinGW г ++! Это ошибка компилятора или я что-то упускаю? Может ли кто-нибудь проверить это в VS, пожалуйста?

Я считаю себя опытным программистом на C++, постоянно использующим полиморфизм, ссылки на основе стека, временные объекты (стандарт C++ 12.2) и т. Д. Поэтому я знаю, что необходимо продлить срок службы.

Такое поведение возникает только при определении деструктора в базе (виртуальном или нет) и использовании временного, i. е. Ниже использование производит «полученные»:

int main() 
{ 
    Derived d; 
    Composite c(d); 
    c.testRef(); 
} 
+2

Может быть неопределенным поведением, если temp был уничтожен и все же захвачен (по ссылке ref) в Composite c. –

+2

Ваш временный объект будет уничтожен, прежде чем вы вызовете 'c.testRef'. В коде отображается неопределенное поведение. Фактически, он падает [здесь] (http://ideone.com/xGQilt). – mfontanini

+0

@mfontanini: А как насчет удлинения продолжительности жизни? Почему я могу выполнить 'const Derived & ref = createDerived();', который возвращает Derived? Например, [здесь] (http://stackoverflow.com/questions/4086508/const-reference-for-temporary-lifetime-lengthening). – Philip

ответ

5
Composite c((Derived())); 

Эта строка создает временный объект типа Derived, передает его в конструктор c, а затем уничтожает временный объект. После этого все ставки отключены.

2
Composite c((Derived())); 

Когда вы определили деструктор базы и программы оставить Композитный конструктор, деструктор Производные и база выполнена. Чтобы избежать ошибки при вызове виртуальной функции Base в деструкторе базы (теперь Derived разрушен), программа перемещает виртуальную функциональную точку (которая является всего лишь адресом объекта этого тестового кода) из таблицы виртуальных функций, полученной из база. Если вы не определяете деструктор, то ничего не делайте. Адрес по-прежнему указывает на таблицу виртуальных функций Derived.

c.testRef(); 

Реф все еще получает адрес объекта и адрес таблицы виртуальных функций и вызывает функцию в таблице. Таким образом, разница существует.

Я тестирую VC 8.0 и проверяю память. Это происходит потому, что некоторые виды «удачливы».

+0

+1 для объяснения причин, почему вызывается базовая реализация. – Philip