ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога 10 июня 2010 года. Спасибо за отличный вопрос!
почему было принято решение не заставлять константы использовать модификатор static, если они считаются статическими?
Предположим, что константы считаются статическими. Есть три возможных варианта:
Сделать статические необязательными : "const int x ..." или "static const int x ..." допустимы.
Сделать статическим обязательным : «const int x ...» недопустимо, «static const int x ...» допустимо
Сделать статические недопустимыми : «const int x ...» допустимо, «static const int x ...» недопустимо.
Ваш вопрос: почему мы выбрали (3)?
В проектных заметках 1999 года не сказано; Я только что проверил. Но мы можем сделать вывод, что, вероятно, происходило в голове дизайнера языков.
Проблема с (1) состоит в том, что вы можете прочитать код, который использует как "const int x ...", так и "static const int y ...", и тогда вы, естественно, спросите себя "в чем разница?" Поскольку для непостоянных полей и методов по умолчанию используется значение «экземпляр», если не «статический», естественным выводом будет то, что некоторые константы относятся к экземпляру, а некоторые - к типу, и этот вывод будет неверным. Это плохо, потому что вводит в заблуждение.
Проблема с (2) в том, что сначала он избыточен. Это просто больше печатать без добавления ясности или выразительности к языку. И во-вторых, я не знаю о вас, но лично я ненавижу, когда компилятор выдает мне ошибку: «Вы забыли сказать волшебное слово прямо здесь. Я знаю, что вы забыли сказать волшебное слово, я на сто процентов способен выяснить, что волшебное слово должно идти туда, но я не позволю вам выполнить какую-либо работу, пока вы не скажете волшебное слово ".
Проблема с (3) состоит в том, что разработчик должен знать, что const логически подразумевает статический. Тем не менее, как только разработчик узнает этот факт, они узнали это. Это не так, как сложная идея, которую трудно понять.
Решение, представляющее наименьшее количество проблем и затрат для конечного пользователя, - (3).
Интересно сравнить и сопоставить это с другими местами в языке, где принимались разные решения.
Например, перегруженные операторы должны быть как общедоступными, так и статическими. В этом случае снова мы сталкиваемся с тремя вариантами:
сделать общедоступную статическую необязательной,
сделать это требуется, или
сделать это незаконным.
Для перегруженных операторов мы выбрали (2). Поскольку естественным состоянием метода является private / instance, кажется странным и вводящим в заблуждение создание чего-то, похожего на метод public / static, невидимым, поскольку (1) и (3) оба требуют.
В другом примере виртуальный метод с той же сигнатурой, что и виртуальный метод в базовом классе, должен иметь либо «новый», либо «переопределенный». Опять три варианта.
сделать его необязательным: вы можете сказать новый или переопределить, или вообще ничего, в этом случае мы по умолчанию устанавливаем новый.
сделайте это обязательным: вы должны сказать новый или переопределить, или
сделать его незаконным: вы вообще не можете сказать новое, поэтому, если вы не говорите «переопределить», оно автоматически становится новым.
В этом случае мы выбрали (1), потому что это лучше всего подходит для ситуации с хрупким базовым классом, когда кто-то добавляет виртуальный метод к базовому классу, который, как вы не понимаете, теперь переопределяет. Это выдает предупреждение, но не ошибку.
Я хочу сказать, что каждая из этих ситуаций должна рассматриваться в каждом конкретном случае. Здесь нет большого общего руководства.