views:

138

answers:

3

hey everyone :)

i am a new programmer in c++. and i am using templates for the first time.

i have an abstract class and another class extending it. but all the protected members of the abstract class are not recognised by the other class:

class0.h:

template<class T>
class class0 {

protected:
    char p;
public:
    char getChar();
};

**class1.h**
template<class T>
class class1:public class0<T> {
public:
    void printChar();
};
template<class T>
void class1<T>::printChar(){
    cout<< p<<endl;//p was not declared in this scope
}

thank you. have a great week =)

+12  A: 

The reason that this is happening is to do with the lookup rules for templates.

p isn't a dependent expression because it is just an identifier and not something that depends on the template parameter. This means that base classes that are dependent on the template parameter won't be searched to resolve the name p. To work around this issue you need to use something that does depend on the template parameter. Using this-> will do this.

e.g.

cout << this->p << endl;
Charles Bailey
Thank you! that helped =) have a good day!
yonka
@yonka: You should accept his answer.
GMan
@GMan: I don't know; litb has posted an answer now. :-)
Charles Bailey
@Charles nah i'm just nitpicking on this :)
Johannes Schaub - litb
+1  A: 

I don't get that compiler error in VC9. However, there are several problems with the code: First, it doesn't need to be a template class as it's currently written...but maybe you just simplified it for this question? Second, The base class should have a virtual destructor.

#include <iostream>

using namespace std;

class class0 {
public:
   virtual ~class0(){}

protected:
    char p;
public:
    char getChar();
};

class class1 : public class0 {
public:
    void printChar();
};

void class1::printChar(){
    cout << p << endl;//p was not declared in this scope
}

int main() {
   class1 c;
   c.printChar();
   return 1;
}

Since you're learning about templates, I would suggest not mixing concepts (inheritance & templates) while learning. Start with a simple example like this...

#include <iostream>
#include <string>

using namespace std;

template <typename T>
T add(const T& a, const T& b) {
   return a + b;
}

int main() {
   int x = 5;
   int y = 5;

   int z = add(x, y);
   cout << z << endl;

   string s1("Hello, ");
   string s2("World!");

   string s3 = add(s1, s2);
   cout << s3 << endl;

   return 1;
}

The important concept in the code above is that we wrote ONE function that knows how to add integers and strings (and many other types for that matter).

dgnorton
Why should the base class have a virtual destructor? Templates are often used to implement parametric polymorphism, and virtual deletion is only useful for dynamic polymorphism (and only if deletion is done polymorphically).
Ben Voigt
The Visual Studio 2008 compiler is known not to correctly implement the template lookup rules in this case. This is why you don't see the error.
Charles Bailey
@Ben Voigt, good point but the OP is just starting with templates and I was guessing that they probably haven't covered that yet. But it does look like they've covered inheritance and unless he's specifically going for compile-time polymorph it's safest to make the base destructor virtual.
dgnorton
@Charles Bailey, thanks for the info. I will read up on that.
dgnorton
@dgnorton: As a general guideline, the base class doesn't need a virtual destructor if it doesn't have any other virtual functions. That's the case here. It would be very rare to polymorphically delete a class that isn't polymorphic.
Ben Voigt
+6  A: 

For a name to be looked up in a dependent base class, two conditions need to be satisfied

  • It's necessary that the lookup is not unqualified
  • It's necessary that the name is dependent

These rules as stated in C++03 are different from the rules stated by unrevised C++98, where satisfying the second bullet (making a name dependent) was sufficient for finding names declared in dependent base classes.

A dependent name is looked up at instantiation time and a lookup other than unqualified lookup will not ignore dependent base classes. Both of these conditions need to be satisfied to find a name declared in a dependent base class, neither of them alone is sufficient. To satisfy both conditions you can use various constructs

this->p
class1::p

Both names p are dependent and the first version uses class member access lookup and the second version uses qualified name lookup.

Johannes Schaub - litb