Должны ли функции / переменные класса быть объявлены перед использованием?

Так что я узнал о занятиях и наткнулся на то, что нашел довольно неловким для меня.

class Nebla
{
public:
int test()
{
printout();
return x;
}

void printout()
{
printout2();
}

private:
int x,y;
void printout2()
{
cout<<"Testing my class";
}
};

Я обнаружил, что в классе я могу использовать функции, прежде чем объявить их (прототип их)

Вы можете видеть, что я использовал printout() , printout2() до объявления.

И я могу использовать переменные также до объявления их

Вы можете видеть, что я сделал return x; перед объявлением х.

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

Спасибо

12

Решение

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

Я полагаю, что причина того, что ваш пример работает, состоит в том, что тела вашего test а также printout действительно не там, где они появляются в вашем файле. Код

class MyClass {
void someFun() {
x = 5;
}
int x;
};

…который, по-видимому, нарушает правило необходимости объявлять переменные перед их использованием, фактически эквивалентен:

class MyClass {
void someFun();
int x;
};

void MyClass::someFun() {
x = 5;
}

Как только мы переписываем это так, становится очевидно, что материал внутри вашего MyClass определение на самом деле список декларации. И те могут быть в любом порядке. Вы не полагаетесь на x пока не объявлено. Я знаю, что это правда, потому что если бы вы переписали пример следующим образом,

void MyClass::someFun() {
x = 5;
}

class MyClass {
void someFun();
int x;
};

…это больше не будет компилироваться! Итак, определение класса идет первым (с его полным списком членов), а затем ваши методы могут использовать любой член, не обращая внимания на порядок, в котором они объявлены в классе.

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

Спасибо, что заставили меня исследовать это; Я узнал что-то новое сегодня. 🙂

16

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

Просто чтобы прояснить, это требуется стандартом C ++, а не только тем, как несколько компиляторов обрабатывают определения классов.

N3242 3.3.7:

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

4

Помимо хорошего ответа Филиппа, Страуструп дает хорошее объяснение Правила поиска имени в Дизайн и эволюция C ++. Это описано в «6.3 Разъяснения». В 6.3.1.1, «Правила поиска имени ARM», он упоминает 2 правила, определенные в РУКА:

[1] Правило переопределения типа: имя типа не может быть переопределено в классе после его использования там.

[2] Правило переписывания: встроенные функции-члены анализируются так, как если бы они были определены сразу после окончания объявлений их классов.

Таким образом, в вашем случае будет применяться правило перезаписи (как выводил Филипп), поэтому вы можете пересылать ссылки на этих учеников.

Эта книга может представлять большой исторический интерес (она написана в 1994 году), но я думаю, что эти правила применяются сегодня так же.

1

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

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

0
По вопросам рекламы [email protected]