简体   繁体   中英

Name lookup of qualified base class

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; inside f() refer to D::S and not ::S ?

Within the body of the class D::S the name S refers to itself, obviously. This is called the "injected class name". You can think of it as though there is a public member typedef in D::S with its own name, S .

  • How does (1) work - I would have though that the name of the base class is D::S specifically

X derives from D::S , because you said so in the base class list of X .

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 outside X . Because the injected class name S is a member of D::S , it gets found in X , 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 of X ).

As an analogy consider this example using a member typedef declared in D::S :

namespace D {
  struct S {
    struct S { S(){std::cout << "D::S\n";} };
    typedef S AnotherName;
  };
}

struct X : D::S {
  X() : AnotherName() { }
};

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 like AnotherName .

  • Are (1) and (2) both required to work?

Yes.

(2) works because D::S is the fully-qualified named of S so it refers to the same type, but using its "full name" that non-members must use to refer to the type.

  • Why does S s; inside f() refer to D::S and not ::S ?

Because like the constructor, f() is a member of X so name lookup looks inside the scope of X (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 name S as a member of the base class and stops looking.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM