Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A class name introduced inside a class is not treated as a nested class name

Tags:

c++

c++11

g++

Take these class definitions:

Class definition 1:

struct A 
{
   struct B* m_b;
};

Class definition 2:

struct A 
{
   struct B;
   B* m_b;
};

Both the class defintions should declare B as a nested class. At least, that's what I thought by reading the following from the draft C++11 standard:

9.1/2 A class declaration introduces the class name into the scope where it is declared and hides any class, variable, function, or other declaration of that name in an enclosing scope (3.3). If a class name is declared in a scope where a variable, function, or enumerator of the same name is also declared, then when both declarations are in scope, the class can be referred to only using an elaborated-type-specifier `

However, g++ 4.8.2 treats them differently. In the first definition, it treats B as a class that is a peer to A.

The following program is built successfully:

struct A 
{
   struct B* m_b;
};

void myfun(const B& b )
{
}

int main()
{
   A a;
   myfun(*a.m_b);
}

while the following program does not:

struct A 
{
   struct B;
   B* m_b;
};

void myfun(const B& b )
{
}

int main()
{
   A a;
   myfun(*a.m_b);
}

I understand why the second program does not compile but I don't understand why the first program is built successfully.

Am I missing something in the interpretation of the standard?

Is g++ 4.8.2 correct in compiling the first program?

like image 665
R Sahu Avatar asked Jun 26 '14 06:06

R Sahu


People also ask

Can I declare a class inside a class?

The Java programming language allows you to define a class within another class. Such a class is called a nested class and is illustrated here: class OuterClass { ... class NestedClass { ... } }

Can we define a class inside a class in C++?

A nested class is declared within the scope of another class. The name of a nested class is local to its enclosing class.

How is a nested class defined?

A nested class is a class which is declared in another enclosing class. A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed.

What is nested class in OOP?

In object-oriented programming (OOP), an inner class or nested class is a class declared entirely within the body of another class or interface. It is distinguished from a subclass.


1 Answers

g++'s behavior here is entirely correct. This is specified in §3.3.2 [basic.scope.pdecl]/p7 of the standard:

The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

  • for a declaration of the form
    class-key attribute-specifier-seqopt identifier ;
    the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
  • for an elaborated-type-specifier of the form
    class-key identifier
    if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration*, the identifier is declared in the smallest namespace or block scope that contains the declaration.

Note that in the second case the declaration is always placed in a namespace or block scope, never a class scope, so it can never declare a nested class. Also, in the second case, a lookup will be performed and only if a previously declared type-name is not found will the elaborated-type-specifier be taken to declare a new name (§3.4.4 [basic.lookup.elab]/p2, §9.1 [class.name]/p3 note).


* Friend declarations have their own weird rules. The names first declared in friend declarations are still placed in namespace (for non-local classes) or block (for local classes) scope, but they are not made visible for most name lookup (except for ADL in case of functions) until they are also declared in the scope containing them. The rules for non-local classes are specified in §7.3.1.2 [namespace.memdef]/p3:

If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.

The rules for local classes are specified in §11.3 [class.friend]/p11:

If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope. [...] For a friend class declaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matching declaration is provided in the innermost enclosing non-class scope.

like image 130
T.C. Avatar answered Oct 23 '22 15:10

T.C.