calling functions above their declaration

2020-05-28 06:02发布

问题:

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()
    {
    }
};

What is the rationale behind this inconsistency of treating calls to functions above their declaration? How come I can do it inside a class, but not inside a namespace or at global scope?

回答1:

You can define member functions either inside the class, or after the class declaration, or some of each.

To get some consistency here, the rules for a class with functions defined inline is that it still has to be compiled as if the functions were defined after the class.

Your code

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

     static void bar()
     {     }
 }; 

compiles the same as

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

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

 void C::bar()
 {     }

and now there is no magic in the visibility, because the functions can all see everything declared in the class.



回答2:

  1. Namespaces can be reopened and new things can be added in any place. Classes cannot be reopened - all their contents must be put in single place.

  2. Function prototypes are legal in namespaces but not in classes.

You can write

namespace n
{
    void foo();

    void bar()
    {
        foo();
    }

    void foo()
    {
    }
}

But not

class C
{
    void foo();

    void bar()
    {
        foo();
    }

    void foo()
    {
    }
}

So classes need such feature much more and it is much easier to implement it for them than for namespaces.



回答3:

Well maybe because you have your class declaration in one place, and the compiler can easily obtain the information of it's members.

A namespace, on the other hand, can have it's stuff in tons of different files, and you can't expect the compiler to look through them, because it doesn't know where to look in the first place.

To avoid this, just use function prototypes.



回答4:

I'm not sure but my thought is that a class is somewhat an object (badly used) where all its internal components work together (generally speaking), its member will definitely need its methods.

But a namespace is different, functions are not related. It means that a function isnt intended to work with every other functions inside the namespace.

So splitting declaration and definitions is the best thing you could do.

If foo() needs bar() its most likely going to be in the same declaration file, and would work that way



回答5:

See the quote below from the Standard

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 };
};