Ошибка определения ошибки Looser в С++

Следующий код генерирует ошибку "Ошибка определения маркера Looser". Не могли бы вы помочь мне преодолеть эту ошибку?

class base
{
    virtual void abc() throw (exp1);
}

void base::abc() throw (exp1)
{
    ......
}

class sub : public base
{
    void abc() throw(exp1, exp2);
}

void sub::abc() throw (exp1, exp2)
{
    .....
}

Ответ 1

Проблема возникает из-за того, что подкласс должен использоваться везде, где может использоваться базовый класс, и поэтому не должен генерировать типы исключений, отличные от тех, которые указаны в базовом классе.

Существует три решения:

  • Измените спецификатор базового класса, чтобы включить каждый тип исключения, который может понадобиться любому подклассу
  • Изменить каждый подкласс для обработки каждого типа исключения, кроме тех, которые указаны в базовом классе
  • Удалить спецификаторы исключений.

Я бы предложил их удалить; они широко расцениваются как плохая идея, отчасти из-за таких проблем. Как указывает Маттиу, стандарт согласен, и спецификаторы исключений должны быть устаревшими в следующей версии Стандарта.

Ответ 2

Когда вы переопределяете виртуальный метод с помощью спецификатора throw в производном классе, метод в производном классе не может вызывать больше исключений, чем метод в суперклассе. Если вам разрешили это сделать, вы можете разорвать контракт, созданный публичным API суперкласса, переопределив методы в подклассе.

В вашем примере вы говорите, что base:: abc может только throw exp1. Однако, если у вас есть указатель базы типов, который действительно указывает на экземпляр sub, внезапно abc может выдать exp2 в дополнение к exp1.

Чтобы устранить проблему, вам нужно удалить exp2 из спецификатора throw в подклассе или добавить exp2 в спецификатор throw суперкласса.

Ответ 3

Предположим, что я пытаюсь

base *b = new sub;
b->abc();

Основываясь на спецификаторе throw в base::abc, я ожидаю, что он будет только бросать exp1; но sub::abc говорит, что он также может бросать exp2.

Если sub::abc действительно может выбросить exp2, добавьте exp2 в список того, что может base::abc. Если нет, удалите его из списка sub::abc.

И лучше: не используйте спецификаторы throw. Для получения дополнительной информации см. Может ли кто-нибудь объяснить спецификации исключения С++ для меня? и http://www.gotw.ca/publications/mill22.htm.