Search code examples
c++data-members

C++ Name Resolution in Template Subclass-of-Subclass


I am trying to access base-class data in my C++ code without using the "this" pointer. My classes are templated, and ClassA is the base class for ClassB, which is the base class for ClassC. All classes are publicly derived from their base classes. I found this discussion which gets me half-way to a solution, but doesn't resolve it completely:

Why do I have to access template base class members through the this pointer?

That page suggests I should be able to fix my problem with the "using" statement. Here is an example of what I am trying to do:

#include <iostream>

template <typename FP>
class ClassA
{
    protected:
    FP a ;
} ;

template <typename FP>
class ClassB : public ClassA <FP>
{
    using ClassA <FP> :: a ;
    public:
    void fooB ( void ) { std:: cout << a << std::endl ; }
} ;

template <typename FP>
class ClassC : public ClassB <FP>
{
    using ClassA <FP> :: a ;
    public:
    void fooC ( void ) { std:: cout << a << std::endl ; }
} ;

int main ( int argc, char *argv[] ) 
{
    ClassB <double> tempB ;
    ClassC <double> tempC ;

    tempB.fooB ( ) ;
    tempC.fooC ( ) ;

    return 0 ;
}

The code above fails to compile, giving the error below:

stepTWO.cpp: In instantiation of ‘class ClassC<double>’:
stepTWO.cpp:30:25:   required from here
stepTWO.cpp:8:12: error: ‘double ClassA<double>::a’ is protected
         FP a ;
            ^
 stepTWO.cpp:20:11: error: within this context
     class ClassC : public ClassB <FP>

What I've found is that "using" will make the variable accessible in either ClassB or ClassC, but not both. If I put the using statement in both classes, I get the error shown above. All inheritance is done through public derivation.

Does anyone know of a solution to make this work? (Other than using "this" or fully-qualified scope names to access my data elements?)


Solution

  • Your problem here is that in ClassB the using ClassA <FP> :: a ; is in the private section of the class. That means a derived class will not be able to access it. What you need to do is put it in a protected section like the variable is declared ClassA. Doing that you get:

    #include <iostream>
    
    template <typename FP>
    class ClassA
    {
        protected:
        FP a ;
    } ;
    
    template <typename FP>
    class ClassB : public ClassA <FP>
    {
        protected:
        using ClassA <FP> :: a ; // protected so it can be inherited
        public:
        void fooB ( void ) { std:: cout << a << std::endl ; }
    } ;
    
    template <typename FP>
    class ClassC : public ClassB <FP>
    {
        using ClassA <FP> :: a ;
        public:
        void fooC ( void ) { std:: cout << a << std::endl ; }
    } ;
    
    int main ( int argc, char *argv[] ) 
    {
        ClassB <double> tempB ;
        ClassC <double> tempC ;
    
        tempB.fooB ( ) ;
        tempC.fooC ( ) ;
    
        return 0 ;
    }