When base is not template class, then the public member functions are inherited and compiler calls in base class functions from derived class.
Simple example with non-template class
The MFDerived::test( ) calls a function “funda( )” which is located in MFBase class.
#include <iostream> //main header
using namespace std; //namespace
class MFBase
{
public:
void funda()
{
cout << "MFBase::funda() << endl;
}
};
class MFDerived : public MFBase
{
public:
void test()
{
funda(); // calls function in MFBase
}
};
int main()
{
MFDerived d;
d.test();
return 0;
}
Same Example with Template Class
When the base class is template, then compiler cannot simply call base class members in derived class, this is because, now the base is not one class but a family of classes. The compiler can not know how the base class template will be instantiated and whether a specific member function of base will be available in specific instantiation.
#include <iostream> //main header
using namespace std; //namespace
template<typename T>
class MFBase
{
T x;
public:
void funda()
{
cout << "Base<T>::funda( )" << endl;
}
};
template<typename T>
class MFDerived : public MFBase<T>
{
public:
void test()
{
funda(); // ERROR
}
};
int main()
{
MFDerived<int> d; //This line will Error out
d.test();
return 0;
}
Specific reason for restriction
The C++ compiler cannot generate code to access members directly from base class. Probably, in some instantiation of base class some specific member may not be present or it deleted.
In the following code, the function “funda( )” is deleted in “int” instantiation, i.e., inside MFBase<int>. Therefore, there is no meaning in calling this function from MFDerived<int>. However, for other possible instantiations, the function “funda( )” still exists and they can call this base class function.
#include <iostream> //main header
using namespace std; //namespace
template<typename T>
class MFBase
{
T x;
public:
void funda()
{
cout << "Base<T>::funda( )" << endl;
}
};
template<>
class MFBase<int>
{
int x;
public:
void funda() = delete;
};
template<typename T>
class MFDerived : public MFBase<T>
{
public:
void test()
{
funda(); // ERROR
}
};
int main()
{
MFDerived<int> d; //This line will Error out
d.test();
return 0;
}
Call to MFDerived::test () will result in an error that funda( ) is not available in the Derived class in MFBase<int> specialization.
There are 3 ways to enable compiler to call printval ( ).
this pointer: Use of this pointer to enable compiler understand that the member is coming from base class
template<typename T>
void MFDerived<T>::test()
{
this->funda(); // this pointer
}
Using Directive: Employing a using declaration to bring hidden base class names into a derived class’s scope
class MFDerived : public MFBase<T>
{
using MFBase<T>::funda;
void test()
{
funda(); // funda from base is available
}
};
Scope resolution operator: Providing an explicit Base class qualification using scope resolution operator.
template<typename T>
void MFDerived<T>::test()
{
MFBase<T>::funda(); //from MFBase<T> scope
}