Как стать автором
Обновить

Неожиданное коварство параметров по умолчанию или язык мой — враг мой

Время на прочтение 3 мин
Количество просмотров 12K
Хочется поделиться одним поучительным примером того, как, казалось бы, совершенно безобидная возможность языка программирования может обвести вокруг пальца даже опытного разработчика.

Вот пример кода. Вопрос традиционный, что напечатает программа? Постарайтесь скомпилировать и выполнить этот очень простой код «в уме», так будет интереснее.

#include <iostream>
using namespace std;

class A {
public:
    virtual void Foo (int n = 10) {
        cout << "A::Foo, n = " << n << endl;
    }
};

class B : public A {
public:
    virtual void Foo (int n = 20) {
        cout << "B::Foo, n = " << n << endl;
    }
};

int main() {
    A * pa = new B ();
    pa->Foo ();

    return 0;
}


Не заглядывайте в ответ! Ну что, определились? Смелее!

B::Foo, n = 10

Те из вас, кто ответил B::Foo, n = 20, наверняка в недоумении. Как же так, это же виртуальная функция?! Да нет, все верно, вызвана функция из класса B. А вот значение параметра… неужели…

Увы, это так! Значение по умолчанию «приехало» совсем не из той функции, которая была вызвана.

Прежде чем рассказать, как это произошло, сделаем маленькое замечание. Если вы ответили A::Foo, n = 10, скорее всего, вы новичок в С++. Это не страшно, мы все когда-то начинали, просто почитайте побольше про виртуальные функции и вам станет понятен подвох этого примера.

Итак, кто виноват и что делать?

Компилятор строго следует стандарту языка, предписывающему подставить в код вызова функции значения параметров по умолчанию исходя из статического типа указателя, по которому осуществляется вызов виртуальной функции. Это A * в нашем случае, а значит значения параметра будет взято из декларации функции A::Foo.

Для сомневающихся — §8.3.6, пункт 10 в текущем working paper стандарта ISO/IEC 14882: Programming Language C++. (Ссылка на working paper дана просто по причине его бесплатной доступности. В действующем стандарте 1998 года этот пункт находится в той же редакции.)

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

Виноват ли компилятор? Автор готов с уверенностью утверждать, что да. Предупреждение о том, что при переопределении виртуальной функции изменены значения параметров по умолчанию, вполне по силам современному компилятору. Увы, и /W4 и -Wextra остались молчаливо безучастны. (Для проверки использовались Visual C++ 2008 SP1 и gcc 3.4.4.)

Тем не менее, крайне желательное предупреждение компилятора в этой ситуации — не панацея. Разумный практический выход — правило, запрещающее или, по-крайней мере, ограничивающее использование параметров по умолчанию исключительно невиртуальными функциями. Сурово? Да.

Автор не случайно назвал этот пример поучительным. Очень интересно в этой связи посмотреть на параметры по умолчанию в других популярных языках. А также порассуждать о соотношении между гибкостью и универсальностью языка и объеме прилагающихся к нему правил и рекомендаций хорошего стиля.

Оговорки. Ни в коем случае не следует понимать эту статью как критику качества языка программирования C++ в целом. Автор придерживается мнения, что С++ обладает массой уникальных преимуществ и во многих случаях является единственно возможным выбором. Данная публикация преследует две цели: предостеречь недостаточно искушенных пользователей C++ и дать пищу для размышлений о том, что не всегда богатые выразительные способности языка дают нам больше пользы, чем вреда.

P.S. На самом деле это первый пост автора из песочницы, огромная благодарность хабраюзеру no_smoking за любезно предоставленный инвайт. Теперь ждите продолжения!
Теги:
Хабы:
+98
Комментарии 346
Комментарии Комментарии 346

Публикации

Истории

Работа

QT разработчик
13 вакансий
Программист C++
121 вакансия

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн