Вопрос по forward-declaration, c++, class, namespaces, scope – вызов функций выше их декларации

6
void foo()
{
    bar();          // error: ‘bar’ has not been declared
}

void bar()
{
}

namespace N
{
    void foo()
    {
        N::bar();   // error: ‘bar’ is not a member of ‘N’
    }

    void bar()
    {
    }
}

class C
{
    static void foo()
    {
        C::bar();   // works just fine
    }

    static void bar()
    {
    }
};

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

@ Аноним, это ничего не меняет SingerOfTheFall
И каков результат после удаления статики из статической пустоты foo ?? perilbrain
Возможно, компилятор проходит несколько раз через реализации метода класса в объявлении класса, в то время как & quot; C & quot; Компилятор проходит только один раз. Может быть наследие, так как foo () по сути является C-функцией Roman Saveljev

Ваш Ответ

5   ответов
0

3.3.7 Class scope [basic.scope.class]

1) The following rules describe the scope of names declared in classes. 1) The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, and brace-or-equalinitializers of non-static data members in that class (including such things in nested classes).

2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

typedef int c;
enum { i = 1 };

class X {
     char v[i]; // error: i refers to ::i
                // but when reevaluated is X::i
     int f() { return sizeof(c); } // OK: X::c
     char c;
     enum { i = 2 };
};
0

class несколькоobject (плохо используется), где все его внутренние компоненты работают вместе (вообще говоря), его члену определенно понадобятся его методы.

Но пространство имен отличается, функции не связаны. Это означает, что функция не предназначена для работы с любыми другими функциями внутри пространства имен.

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

Еслиfoo() потребностиbar() Скорее всего, он будет в том же файле декларации, и будет работать таким образом

3

либо после объявления класса, либо некоторых из них.

Чтобы получить последовательностьhereправила для класса с определенными встроенными функциями таковы, что он все еще должен быть скомпилирован, как если бы функции были определеныafter класс.

Ваш код

class C {
     static void foo()
     {
         C::bar();   // works just fine 
     }

     static void bar()
     {     }
 }; 

компилируется так же, как

class C {
     static void foo();
     static void bar();
 }; 

 void C::foo()
 {  C::bar();  }

 void C::bar()
 {     }

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

1

Classes cannot be reopened - all their contents must be put in single place.

Function prototypes are legal in namespaces but not in classes.

Ты можешь написать

namespace n
{
    void foo();

    void bar()
    {
        foo();
    }

    void foo()
    {
    }
}

Но нет

class C
{
    void foo();

    void bar()
    {
        foo();
    }

    void foo()
    {
    }
}

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

0

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

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

Чтобы избежать этого, просто используйтефункциональные прототипы.

Похожие вопросы