Ловля исключений по ссылке - PullRequest
6 голосов
/ 02 декабря 2011

В этом учебном пособии по C ++ , в разделе, озаглавленном «Стандартные исключения», есть этот пример кода, который использует класс, производный от стандартного класса исключений в STL:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex; //Declares an instance of myexception outside of the main function

int main () {
  try
  {
    throw myex;
  }
  catch (exception& e) //My question is regarding this line of code
  {
    cout << e.what() << endl;
  }
  return 0;
}

Этот код распечатывает My exception happened.Однако, если я удалю амперсанд, он напечатает std::exception, что и происходит, когда вы вызываете what() со стандартным классом исключений, а не с производным классом.

Веб-сайт дает такое объяснение:

Мы поместили обработчик, который перехватывает объекты исключений по ссылке (обратите внимание на амперсанд и после типа), поэтому он также отлавливает классы, полученные из исключения, как наш объект myex класса myexception.

Является ли бросание myex чем-то вроде "вызова функции catch и передачи myex в качестве параметра"?Потому что в этом случае я бы подумал, что не имеет значения, выбрасываете ли вы исключение по значению или по ссылке (это то, что амперсанд делает правильно?), Потому что вы все равно выбрасываете myexception, а не exception.А из-за динамического связывания и полиморфизма или чего-то в этом роде e.what() все равно должен печатать My exception happened, а не std::exception.

Ответы [ 3 ]

10 голосов
/ 02 декабря 2011

Это происходит из-за нарезки объектов.

Если вы назначите объект производного класса экземпляру базового класса (как в случае использования копии c'or при передаче по значению), вся информация производного класса будет потеряна (разрезана).

Например,

class Base {
   int baseInfo;
};

class Derived : public Base
{
   int someInfo;
};

Тогда, если бы вы написали это:

Derived myDerivedInstance;

Base baseInstance = myDerivedInstance;

Затем «someInfo» в myDerivedInstance обрезается в baseInstance.

3 голосов
/ 02 декабря 2011

Вы можете думать об этом так, но (как при вызове функции) исключение передается по значению в обработчик catch. Поскольку он передается по значению, он копируется в локальный std::exception обработчик catch. Это достигается с помощью конструктора копирования std::exception, и в этом случае копия больше не содержит ни личных данных, хранящихся в myexception, ни производных функций. Функции делают то же самое. Это называется «разрезанием объектов», и поэтому вы никогда не храните виртуальные базовые типы по значению, только по указателю или по ссылке. Вы бы увидели такое же поведение с std::vector<std::exception>. Содержащиеся элементы потеряют все производные данные.

2 голосов
/ 02 декабря 2011

В C ++ вы можете использовать семантику копирования или семантику ссылок при передаче и перехвате объектов, при этом копирование по умолчанию наследуется от C. Когда вы используете семантику копирования, программа просто создает объект исключение от myexception .Поскольку исключение ничего не знает о его потомках, вы теряете определенные части объекта myexception .

Именно поэтому вы всегда должны использовать ссылки или указатели, когда вам нужен полиморфизм.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...