Why How to Call Base Template Class Method from Derived Class

Why can I call base template class method from derived class

template <class T>
struct A {
void f(){}
};

template <class T>
struct B : public A <T> {
void f2() { f(); } // calling base function - will not compile
};

In the derived template, the expression f() is not dependent on any template argument, so the compiler attempts to resolve it during the first phase lookup. At this point, the template has not yet been instantiated with the type, and the compiler won't look into the base A<T>. The reason is that the compiler could not possibly know whether for the type of the instantiation there is a specialization of A<T> that might not contain any members.

The solution is to make the expression dependent, the simplest way would be to qualify with this->:

template <typename T>
void B<T>::f2() { this->f(); }

As the expression is now dependent, lookup is delayed until the second phase, where the type is substituted and A<T> is a concrete type. Another alternative is qualifying with the class where it is defined:

template <typename T>
void B<T>::f2() { A<T>::f(); }

Again the expression becomes dependent and will be resolved during the second phase. The main difference is that in this second case, the call is qualified and thus it does not use dynamic dispatch. If A<T>::f() was virtual it would still execute A<T>::f(), and not the final overrider.


Is the code correct? No. Does VS accept it? Yes.

This is a known non-conformance in the Visual Studio compiler, that does not implement two phase lookup. It delays all lookup inside the template to the second phase and at that point lookup succeeds.

How to call the base class method in C++?

If you want to explicitly use the base's member, make the type explicit like you found:

template <typename base>
struct derived : public base
{
void aFunction()
{
base::function();
}
};

If you would rather have the usual unqualified-lookup behaviour, make this explicit instead:

template <typename base>
struct derived : public base
{
void aFunction()
{
this->function();
}
};

Both of these behave exactly like they do in non-templates.

C++: Calling base class method on derived class member

There are several options with different advantages and disadvantages.

  1. You can make the base class a template like this:
template<class Property>
class Base{
public:
Base(){};
void method(){property.speak();}
Property property;

};

class DerivedA : public Base<A>{
};

class DerivedB : public Base<B>{
};

It is clear and simple, but notice that DerivedA and DerivedB in this case have no common base class, so you can't, e.g. put pointers to them in the same container.


  1. You can use polymorphism.
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;

};

class DerivedA : public Base{
public:
A property;
void method() override { property.speak(); }
};

class DerivedB : public Base{
public:
B property;
void method() override { property.speak(); }
};

This is a bit more complex, involves some code duplication and requires more resources (to store virtual table e.g.), but now the classes really have a common ancestor.


  1. Combine templates and polymorphism
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;

};

template<class Property>
class Derived: public Base {
public:
Property property;
void method() override { property.speak(); }
};

using DerivedA = Derived<A>;
using DerivedB = Derived<B>;

This is actually option #2, but with no code duplication: we make the compiler generate code for us using templates.


  1. Other options. There may be other more specialized options depending on your requirements.

Calling method of template base class

Normally to call a base class function in this case you would write:

this->f();

If f and g were both static, you would of course not be able to do this, so instead you could write

B<T>::f();

This works because B is already in scope at the declaration of C, so the compiler already knows it's a template. If you do B::f() alone, the compiler will give you an error because it knows B is a template so it is supposed to have template arguments.

You might be wondering why you are allowed to omit the template arguments inside the definition of B<T> but not inside the definition of C. To understand this, you need to know that every class has an injected-class-name that behaves like a typedef declared at the very beginning of the class definition. So it is as though the definition of B started with

typedef B<T> B;

Using B inside the definition of B<T> will find the injected-class-name, not the template. But when you are inside C, this B is not visible since it is declared inside B<T>, which is a dependent base class, and dependent base class scopes are not searched during unqualified name lookup (and B is on the left of ::, so the lookup of B is unqualified). This also works:

C::B::f();

In this case, the injected-class-name C is found, and it refers to the dependent type C<T>, so the lookup of B will search inside the dependent base class B<T> and find the desired injected-class-name.

overriding the template base method in derived class?

A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.

A working example

#include <vector>
#include <iostream>

struct BaseOfBase
{ virtual void do_something () = 0; };

template <typename T>
struct Base : public BaseOfBase
{
T val;

void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};

template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };

int main ()
{
std::vector<BaseOfBase*> vpbb;

Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;

bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";

vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);

for ( auto const & pbb : vpbb )
pbb->do_something();
}

Calling derived template class method from base non-template class

There is no clear clean way to do this. The fundamental problem is that there is no such thing as a virtual template method.

The cleanest way I can think of doing this that implements complete type erasure is with a dynamic cast, and a virtual method:

class Base {
public:

virtual bool operator()(const Base &) const=0;
};

template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;

public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}

inline bool operator()(const Base& obj) const override {
const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj);

if (!derived_obj)
{
throw; // Or maybe return false, or something...
}
return (m_db.*m_func)(*derived_obj);
}
};

Obj_Type must also be derived from Base. This gets the job done at runtime, but there is no compile-time type-checking.

The other approach is to bite the bullet, and forego 100% type erasure:

template<typename Obj_Type>
class Base {
public:

virtual bool operator()(const Obj_Type &) const=0;
};

template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base<Obj_Type> {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;

public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}

inline bool operator()(const Obj_Type& obj) const override {
return (m_db.*m_func)(obj);
}
};

So, you can still abstract away operator() on some object to its pure interface, and define the details in the subclass.

Or, another alternative would be a combination of the two:

class SuperBase {
public:

virtual bool operator()(const Base &) const=0;
};

template<typename Obj_Type>
class Base : public SuperBase {
public:

virtual bool operator()(const Obj_Type &) const=0;

bool operator()(const Base &obj) const override
{
// Do the dynamic cast check, and forward it to the other
// operator().
}
};

Accessing base member functions in class derived from template class

When a class template derives from a base class template, the base members are not visible in the derived class template definition. (This makes sense; until you specialize, there is no class, and so there are no members. Explicit specializations can always change the meaning of any given template class.)

In other words, the base template member names are dependent names and not looked up in the first phase of template definition lookup.

There are three ways to get around this. Let's make it concrete with a quick example:

template <typename T> struct Foo
{
int data;
using type = const T &;
void gobble() const;
template <int N> void befuddle();
};

template <typename T> struct X : Foo<T> { /* ... */ };

Now in the context of the derived class template definition, you can...

  1. Qualify the name:

    Foo<T>::data = 10;
    typename Foo<T>::type x;
    Foo<T>::gobble();
    Foo<T>::template befuddle<10>();
  2. Use this:

    this->data = 10;
    this->gobble();
    this->template befuddle<10>();

    (This doesn't work for type names names.)

  3. Use a using declaration:

    using Foo<T>::data;
    using Foo<T>::gobble;
    using type = typename Foo<T>::type;

    data = 10;
    gobble();

    (This doesn't work for template names.)


Update: After your edit, the question is entirely different. Templates don't play a role at all here, since the problem doesn't contain templates, only classes. What's happening is the simple fact that member functions in a derived class hide member functions of the same name in base classes, so the presence of SpecificDerived2::memberFunc hides the base member function. The simple solution is to unhide base members of the same name with a using declaration:

class SpecificDerived2 : public TemplateBase2<float>
{
public:
using TemplateBase2<float>::memberFunc;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

float memberFunc()
{
return 3.14;
}
};


Related Topics



Leave a reply



Submit