Повторная генерация исключения в C++

Не совсем понимаю, почему в следующем коде происходит обрезка объекта класса Child.

#include <iostream>

class Parent
{
public:
    Parent() { }
    virtual void print() { std::cout << "Parent"; }
};

class Child: public Parent
{
public:
    Child() { }
    virtual void print() { std::cout << "Child"; }
};

int main()
{
    try
    {
        try
        {
            throw Child();
        }
        catch (Parent& p)
        {
            std::cout << "Caught Parent p, which is actually a ";
            p.print();
            std::cout << std::endl;
            // обрезка объекта класса Child происходит здесь
            throw p;
        }
    }
    catch (Parent& p)
    {
        std::cout << "Caught Parent p, which is actually a ";
        p.print();
        std::cout << std::endl;
    }

    return 0;
}

В итоге мы получим следующий вывод, который подтверждает, что происходит обрезка:

Caught Parent p, which is actually a Child
Caught Parent p, which is actually a Parent

Я знаю, что если вместо throw p; написать throw;, то компилятор будет использовать точно тот же самый объект в повторном исключении (без копирования), и мы получим следующий вывод:

Caught Parent p, which is actually a Child
Caught Parent p, which is actually a Child


Ответы (1 шт):

Автор решения: Harry

Допишем пару конструкторов

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent() { cout << "Parent::Parent()\n"; }
    Parent(const Parent&) { cout << "Parent::Parent(const Parent&)\n"; }
    virtual void print() { std::cout << "Parent"; }
};

class Child: public Parent
{
public:
    Child() { cout << "Child::Child()\n"; }
    Child(const Child& ) { cout << "Child::Child(const Child&)\n"; }
    virtual void print() { std::cout << "Child"; }
};

int main()
{
    try
    {
        try
        {
            throw Child();
        }
        catch (Parent& p)
        {
            std::cout << "Caught Parent p, which is actually a ";
            p.print();
            std::cout << std::endl;
            // обрезка объекта класса Child происходит здесь
            throw p;
        }
    }
    catch (Parent& p)
    {
        std::cout << "Caught Parent p, which is actually a ";
        p.print();
        std::cout << std::endl;
    }

    return 0;
}

и вывод

Parent::Parent()
Child::Child()
Caught Parent p, which is actually a Child
Parent::Parent(const Parent&)
Caught Parent p, which is actually a Parent

ясно продемонстрирует, что при throw p; генерируется копия объекта Parent.

Что и поясняет наблюдаемое поведение.

→ Ссылка