Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I partially overload a virtual function in a C++ template subclass?

I'm trying to create a non-template base class to create an interface through which I can interact with derived template classes. My hope is to use partial virtual function overloads, but something isn't working, and I'm not sure why. Can anyone explain why I the below code returns:

B match = False
D match = True
E match = False

instead of B,D returning True, and E returning False? I would have thought that the overloaded operator in the derived class would pick up the pointer-to-int '&i' and be called, but it doesn't.

To be clear, I'm not trying to -override- the Base version of match, I am trying to -overload- it, specifically wanting it to have a different, in this case more specialized, interface than the one in Base, which takes over when its function signature is used.

I'm also trying to avoid having to extend the Base class for every flavor of the Derived template that I might instantiate.

Even stranger, and I -might- just be going crazy here, but I swear this was working for me at some point not too long ago! Fwiw I'm on OSX 10.5, using llvm 7.0.0 and clang 700.1.76. Could this be a compiler idiosyncracy?

While I am attempting (unsuccessfully) to use partial overloads here, I'm really open to any approach that solves the problem of picking a template instance function by the type of its arguments, without proliferating classes, if-thens/case or adding specific specializations to the Base class. I'd love to hear it if you have another approach that I could drop in for similar functionality.

Thank you for any insights you can offer!

#include <stdio.h>

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

  virtual bool match( const void *data ) const { return false; }
};

template <class Type>
class Derived: public Base
{
public:
  Derived():Base() {}
  ~Derived() override{}

  virtual bool match( const Type *data ) const { return true; }
};

int main(int argc, char **argv)
{
  Derived<int>   *d = new Derived<int>();
  Derived<float> *e = new Derived<float>();
  Base *b           = d;

  int i;
  printf("B match = %s\n",b->match(&i)?"True":"False");
  printf("D match = %s\n",d->match(&i)?"True":"False");
  printf("E match = %s\n",e->match(&i)?"True":"False");

}
like image 729
Dave Avatar asked Dec 29 '25 01:12

Dave


2 Answers

If you were to manually create Derived<int> as a class, its member function would be:

virtual bool match( const int *data ) const { return true; }

It doesn't override the base class. Hence, when you invoke the function with base class pointer, it executes the base class implementation and when you invoke it with the derived class pointer, it executes the derived class implementation.

You will be able to catch the problem at compile time if you use the override keyword.

template <class Type>
class Derived: public Base
{
public:
  Derived():Base() {}
  ~Derived() override{}

  virtual bool match( const Type *data ) const override { return true; }
};

You should see a compile time error with that change.

See the compiler error at http://ideone.com/8rBQ6B.

Update, in response to OP's comment

If you don't mean to override:

  1. Don't use virtual in the member function declaration.
  2. Bring the base class function into the scope of the derived class by using

    using Base::match
    

    Here's how to do it:

    template <class Type>
    class Derived: public Base
    {
    public:
      Derived():Base() {}
      ~Derived() override{}
    
      using Base::match;
      bool match( const Type *data ) const { return true; }
    };
    
like image 186
R Sahu Avatar answered Dec 31 '25 14:12

R Sahu


The problem here is that Derived::match does not match Base::match. The function signatures of virtual functions have to be the same for the mechanism to work. So with your code Derived::match overloads instead of overriding it.

If we change

virtual bool match( const Type *data ) const { return true; }

To

virtual bool match( const void *data ) const { return true; }

Then we get

B match = True
D match = True

Live Example

like image 32
NathanOliver Avatar answered Dec 31 '25 15:12

NathanOliver



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!