jmasterx
jmasterx

Reputation: 54113

Why can member functions be called before being declared?

I have always been under the impression that C/C++ is parsed in 1 pass, therefore, a symbol must be declared before it can be used.

Thus this does not work:

void a()
{
   b();
}

void b() 
{
}

unless we forward declare void a();

However, I noticed that this does work:

class Foo 
{
  public:
  void a() 
  {
    b();
  }

  void b()
  {
  }
};

Why does this work? If C++ is parsed in a single pass through the code then this should not work I would think because the symbol Foo::b() has not been defined when it is called.

Upvotes: 3

Views: 134

Answers (4)

Ben Voigt
Ben Voigt

Reputation: 283684

Section 3.3.7 of the C++ Standard includes, among other rules, the statement that

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, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).

Basically, this requires that analysis of the mentioned contexts, if they appear inline inside the class definition, is deferred until the entire class definition has been processed just as if you had used an out-of-line definition.

A related rule is found in section 9.2:

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

Upvotes: 0

Christophe
Christophe

Reputation: 73376

The definition of your class:

class Foo 
{
public:
  void a()  {  b(); }
  void b()  {  }
};

has the same meaning than:

class Foo 
{
public:
  void a();
  void b();
};
void Foo::a()  {  b(); }
void Foo::b()  {  }

This is why the function body sees all the members, as if the class was already completely defined. This is by the ways stated in the C++ standard:

3.3.7/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, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).

The compiler still parses the file in a single pass. But the parsing the grammatical construct is only a part of the larger compilation process, in which applying the context to the parsed grammar production plays also a role (see also this SO question).

Upvotes: 1

Jesse Laning
Jesse Laning

Reputation: 490

There are things called forward references (different from forward declaration)

class C
{
public:
   void mutator(int x) { myValue = x; }
   int accessor() const { return myValue; }
private:
   int myValue;
};

here myValue is accessed before it it declared. C++ does not usually allow forward references but for class members it allows them. It is the compilers job to remember the definition of mutator and accessor until it sees myValue

Upvotes: 1

in need of help
in need of help

Reputation: 1622

On the first pass all the class interface is read and thus when the code for function a is compiled it knows that the function b exists in the class Foo

Upvotes: 0

Related Questions