Peter
Peter

Reputation: 11900

C++ template inheritance does not see base class members

Please look at the following code:

template<class MT>
class ClassA {
public:
  int cnt;
};

template<class MT>
class ClassB : public ClassA<MT> {
public:

   void test() {
     cnt++ ;
   }
};

When compiled, g++ gives an error that "cnt" was not declared in the scope.

If I change cnt to this->cnt, it works. However, I am confused. Can someone please explain why would it not work otherwise?

Upvotes: 0

Views: 86

Answers (3)

IdeaHat
IdeaHat

Reputation: 7881

I figured I'd expand Mark B's answer (though he is totally right).

the rules of the language state that you have to qualify it with this-> or base

The rules of the language are there because there are many situations where the compiler simply cannot know where to look for that name at compile time: cnt could exist in the parent class, or it could not.

Take the following example:

template<class MT>
class ClassA {
public:
};

template<class MT>
class ClassB : public ClassA<MT> {
public:

   void test() {
     cnt++ ;
   }
};

template<>
class ClassA<int>
{
public:
  int cnt;
};

How does the compiler know where to find cnt? The parent's members don't exist at declaration time. You can specialize at any time, so this specialization could be in a different file all together, and the specialization in different compilation units could not agree (wacky). The child class could have any sort of parent structure. So the compiler won't even look in the parent (which doesn't exist until instantiation time) until you tell it to.

This leads to the weird (but perfectly logical) behavior below:

template<class MT>
class ClassA {
public:
};

int cnt = 50;
template<class MT>
class ClassB : public ClassA<MT> {
public:

   void test() {
     cnt++ ;
   }
};

template<>
class ClassA<int>
{
public:
  int cnt;
  ClassA(){cnt=0;}
};

template <>
class ClassB<int> : public ClassA<int>
{
public:
  void test() {
    cnt++ ;
  }
};

int main () {

ClassB<int> bi;
ClassB<float> bf;
bi.test();
bf.test();

std::cout << cnt << std::endl;
std::cout << bi.cnt << std::endl;
}

Which yields

51
1

(so the cnt in the general template does not match the cnt in the specialization).

Upvotes: 2

user3033893
user3033893

Reputation: 990

Compiling a template does NOT automatically look into the base class for names. Here's the only explanation I could find on short notice: http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html

An easy workaround is to add a

using ClassA<MT>::cnt;

somewhere to the definition of your ClassB.

Upvotes: 0

Mark B
Mark B

Reputation: 96251

The reason is that cnt is not a dependent name (doesn't depent on the template paremeter), so the rules of the language state that you have to qualify it with this-> or base::.

Upvotes: 5

Related Questions