Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ and injected base name

The following code does not compile in gcc:

namespace One{
   class A{
   };
};

namespace Two{
   class A{
      public:
         void what(){
            cout << "Two::A says what!" << endl;
         }
   };

   class B : public One::A{
      public:
         B(){
            A xx;
            xx.what();
         }
   };

};

And it gives:

gccbug.cpp: In constructor ‘Two::B::B()’:
gccbug.cpp:23: error: ‘class One::A’ has no member named ‘what’

Now, I was told that this is correct behavior (due to injected base name of One::A making A refer to One::A). However, this code compiles in C# (well, after changing a few things), so this seems to be c++ specific.

What I'm wondering is.. why? Is there a specific purpose for injecting the base name "One::A" as "A"?

like image 281
kamziro Avatar asked Feb 26 '12 11:02

kamziro


2 Answers

The only reason I can think of is that in C++ you are likely to refer to the base class name in the initializer list of the constructor, like this:

namespace Two {

  /*...*/

  class B : public One::A {
  public:
     B():A()
     {
        /*...*/
     }
   };
}

Of course the purpose then is different from the one in your example, because you actually declare a local variable inside the constructor, whereas in my example, the A() refers to the object of type A that is implicit in the definition of class B due to inheritance.

However, the situation of my example is more likely to occur, so I guess they thought let's not require the namespace to be made explicit in this case. As a consequence, any reference to A without a namespace is interpreted as referring to the base class, rather than any other class named A, even if it is in the same namespace as the declaration of B.

like image 69
jogojapan Avatar answered Oct 30 '22 17:10

jogojapan


Is there a specific purpose for injecting the base name "One::A" as "A"?

Yes. It is so that you could write this:

namespace N
{
   class A
   {
       A *a;
   };
}

In the absence of injected-name, you've to write N::A *a which is not nice.

Note that it is because of injected-name, the following lines are allowed:

A::A *a1; //ok
A::A::A *a2; //ok 
A::A::A::A *a3; //ok 
A::A::A::A::A *a4; //ok 
//and so on

Online demo

like image 25
Nawaz Avatar answered Oct 30 '22 17:10

Nawaz