Consider this code:
#include <iostream>
namespace D
{
struct S { S(){std::cout << "D::S\n";} };
}
struct S { S(){std::cout << "S\n";} };
struct X: D::S
{
X(): S() {} // (1)
// X(): D::S() {} // (2)
void f() { S s; }
};
int main() { X x; x.f(); }
Output from g++ is:
D::S
D::S
My questions are:
- How does (1) work - I would have though that the name of the base class is
D::S
specifically - Are (1) and (2) both required to work?
- Why does
S s;
insidef()
refer toD::S
and not::S
?
Within the body of the class
D::S
the nameS
refers to itself, obviously. This is called the "injected class name". You can think of it as though there is a public member typedef inD::S
with its own name,S
.X
derives fromD::S
, because you said so in the base class list ofX
.A derived class has access to the names declared in a base class, so name lookup in
X
first looks at its own members and its base class' members, then looks for names in the enclosing scope outsideX
. Because the injected class nameS
is a member ofD::S
, it gets found inX
, that's why (1) works. The type::S
is not found because name lookup finds the injected class name and never looks in the enclosing scope (if it did find::S
the code wouldn't compile, because::S
is not a base class ofX
).As an analogy consider this example using a member typedef declared in
D::S
:This works because the name
AnotherName
is found in the base class, and is a synonym for the type of the base class,D::S
. The injected class name works similarly, except that the name that gets injected is the class' own name,S
, not some other name likeAnotherName
.Yes.
(2) works because
D::S
is the fully-qualified named ofS
so it refers to the same type, but using its "full name" that non-members must use to refer to the type.Because like the constructor,
f()
is a member ofX
so name lookup looks inside the scope ofX
(and its base classes) first, and so finds the injected class name. It never see the type::S
at global scope because it finds the nameS
as a member of the base class and stops looking.