функция — Почему методы структур не должны быть объявлены в C ++?

Взять, к примеру, следующий код:

#include <iostream>
#include <string>

int main()
{
print("Hello!");
}

void print(std::string s) {
std::cout << s << std::endl;
}

При попытке построить это, я получаю следующее:

program.cpp: In function ‘int main()’:
program.cpp:6:16: error: ‘print’ was not declared in this scope

Что имеет смысл.

Так почему я могу использовать аналогичную концепцию в структуре, но не кричать на это?

struct Snake {
...

Snake() {
...
addBlock(Block(...));
}

void addBlock(Block block) {
...
}

void update() {
...
}

} snake1;

Я не только не получаю предупреждения, но и программа на самом деле компилируется! Без ошибок! Это просто природа структур? Что тут происходит? очевидно addBlock(Block) был вызван до того, как метод был объявлен.

29

Решение

struct в C ++ на самом деле class определение, где его содержание public, если не указано иное путем включения защищенного: или частного: раздела.

Когда компилятор видит class или же structсначала переваривает все объявления внутри блока ({}) прежде чем оперировать им.

В случае обычного метода компилятор еще не видел объявленный тип.

15

Другие решения

C ++ стандарт 3.4.1:

.4:

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

Вот почему глобальные переменные и функции нельзя использовать перед предыдущим объявлением.

.5:

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

То же самое, только что написанное снова, поскольку параграф .4 явно ограничил его высказывание «глобальным», этот параграф теперь говорит: «Кстати, это верно и для людей с именами …»

.7:

Имя, используемое в определении класса X вне члена
Тело функции или определение вложенного класса29 должны быть объявлены в одном из
следующие способы: — до его использования в классе X или быть членом
базовый класс X (10.2), или — если X является вложенным классом класса Y (9.7),
до определения X в Y, или должен быть членом базового класса
из Y (этот поиск применяется, в свою очередь, к вмещающим классам Y, начиная
с самым внутренним включающим классом), 30 или — если X является локальным классом
(9.8) или является вложенным классом локального класса, до определения
класс X в блоке, включающем определение класса X, или — если X является
член пространства имен N, или является вложенным классом класса, который является
член N или является локальным классом или вложенным классом в локальном
класс функции, которая является членом N, до определения
класс X в пространстве имен N или в одном из вложенных пространств имен N.

Я думаю, что это говорит обо всем коде, который не находится в исполняемом коде процессора (например, декларативный код).

и наконец интересная часть:

3.3.7 Область действия класса [basic.scope.class]

1 Следующие правила описывают область имен, объявленных в классах.

1) Потенциальная сфера действия
Имя, объявленное в классе, состоит не только из декларативного региона
после точки объявления имени, но и всей функции
тела, фигурные или равные инициализаторы нестатических элементов данных и
аргументы по умолчанию в этом классе (включая такие вещи во вложенных
классы).

2) имя N, используемое в классе S, должно относиться к тому же
декларация в ее контексте и при повторной оценке в завершенном
область применения S. Никаких диагностических данных не требуется для нарушения этого правила.

3)
Если переупорядочение объявлений членов в классе дает альтернативный действительный
Программа в соответствии с (1) и (2), программа плохо сформирована, нет диагностики
требуется.

в частности, к последнему пункту они используют отрицательный способ, чтобы определить, что «любое упорядочение возможно», потому что, если переупорядочение изменит поиск, тогда возникает проблема. Это негативный способ сказать: «Вы можете изменить порядок вещей, и это нормально, это ничего не меняет».

фактически говоря, в классе объявление ищется в двухфазной компиляции.

13

«Зачем Могу ли я провести аналогичную концепцию в структуре, но не кричать на это? «

В struct или же class определение вы представление публичного интерфейса к классу, и это намного легче понять, искать и поддерживать / обновлять этот API, если он представлен в:

  • предсказуемый порядок, с
  • минимальный беспорядок.

Для предсказуемого порядка у людей есть свои собственные стили, и в этом есть немного «искусства», но, например, я использую каждый спецификатор доступа не более одного раза и всегда public до protected до privateто в те, которые я обычно ставлю typedefs, const данные, конструкторы, деструкторы, мутирующие / неконстантные функции, const функции, statics, friends ….

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

Это отличается от функций, которые не являются членами класса — где люди, которым нравится нисходящее программирование, используют объявления функций и скрывают определения позже в файле — в этом:

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

  • Классы с большей вероятностью имеют много очень коротких функций, в основном потому, что они обеспечивают инкапсуляцию и оборачивают множество тривиальных обращений к элементам данных или обеспечивают перегрузку операторов, операторы приведения, неявные конструкторы и другие вспомогательные функции, которые не имеют отношения к не-OO, функции, не являющиеся членами. Это делает постоянное принудительное разделение объявлений и определений более болезненным для многих классов (не столько в общедоступных интерфейсах, где определения могут быть в отдельном файле, но, безусловно, для, например, классов в анонимных пространствах имен, поддерживающих текущий модуль перевода).

  • Лучше всего, чтобы классы не втиснулись в чрезвычайно обширный интерфейс … вам, как правило, нужно функциональное ядро, а затем некоторые удобные вспомогательные функции, после чего стоит подумать о том, что можно добавить как функции, не являющиеся членами. std::string часто утверждается, что имеет слишком много функций-членов, хотя я лично считаю, что это вполне разумно. Тем не менее, это также отличается от заголовочного файла, объявляющего интерфейс библиотеки, где можно ожидать, что исчерпывающие функциональные возможности будут объединены, разделяя даже inline реализация более желательна.

5
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector