Is a namespace required when referring to the base class
Asked Answered
G

1

14

I have code like this:

namespace N {
   class B {
     public:
       virtual void doStuff(B *) = 0;
    };
 }

 // not in a namespace
 class Derived : public N::B {
   public:
       void doStuff(B *); // Should this be N::B, or is B ok?
 };

Do I need the namespace qualifier where Derived refers to it's base class? GCC and MSVC are happy with the code as written, but another compiler complains unless I put the namespace in. What does the C++ standard say?

Geodetic answered 25/11, 2010 at 13:20 Comment(1)
Which compiler complains if that's not a secret?Iinden
I
12

Inside the class definition B is OK. That's the so-called injected class name.

This also refers to templates (not counting dependent bases). E.g.

template <class T> class B{};
template <class T> class C: public B<int>
{
   void f(B* p) {} //same as B<int>* p
   void f(C* p) {} //same as C<T>* p
};

In general the base class (and the class itself) can be referred to inside the class definition without qualification or template arguments.

Quotes from the standard:

9.2 : A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.

From this definition it follows that the name of the class itself is publicly accessible from the class, and therefore is available in derived classes. Which proves my point about B being OK along with N::B because the name B is inherited

Btw, this also explains why the following is invalid:

template <class T> class B{};
template <class T> class C: public B<T>
{
     void f(B* p){} //ERROR
    // the above is invalid!! Base class is dependent therefore 
    //its scope is not considered during unqualified name lookup
     void g(typename C::B* p){} //this is valid, same as B<T>* p  
};

14.6.1 Speaks about injected class names in templates. It is far too long to paste here. Hth

Iinden answered 25/11, 2010 at 13:24 Comment(11)
So why is the compiler complaining ?Gerrilee
@Raveline: Because I forgot the {} :) EditedIinden
As far as I can see, 9.2/2 only says that the class name "Derived" is injected into Derived itself. It doesn't say anything about base classesFleming
@Steve: Since the name is like a public name in the class, it is inherited by the derived classes.Iinden
@Armen: aha! Yep, that does it. So because B is injected into B, it's also therefore in Derived.Fleming
@Steve: Take a look at my update, I think you'll be interested :)Iinden
Sadly, currently C++0x makes typename C::B which is valid C++03 invalid by making C::B a non-dependent name (it's a member of the current instantiation). See DR #1043.Blastogenesis
@Johannes: I don't think it's a problem, since I am betting that everyone considers B<T> more intuitive and clear than typename C::BIinden
@Armen I don't like specifying weird long names in ctor initializer lists, so i like doing template<YYY> struct A : XXX<ZZZ> { A():A::XXX(AAA) { } };. It will be broken formally :(Blastogenesis
@Johannes: Oh, my sincere condolences then :)Iinden
@Johannes: shame they aren't forcing you to put spaces in your initializer list while they're about it ;-pFleming

© 2022 - 2024 — McMap. All rights reserved.