1

Is there a way to force implementation of a method in a child class where the implementation will have a different signature for each derived class?

I know I can do this, using pure virtual:

class Base {
  public:
   virtual void getValue(string& s) = 0;
}

class Derived : public Base {
  public:
   void getValue(string& s);
}

Above, pure virtual getValue in the base class forces the derived class to implement getValue. But what I really want to do is something like this: Force each derived class to implement getValue() but each with a different signature:

class Base {
  public:
   void getValue() = 0;
}

class Derived_A : public Base {
  public:
   void getValue(string& s);
}

class Derived_B : public Base {
  public:
   void getValue(int *j);
}

The problem with the above is that, due to name mangling, each signature is effectively a different function, and thus Derived_A and Derived_B inherit getValue() = 0 and the compiler thinks that they also are abstract.

I've been playing around with some different ways to do this, but it appears to me there is no way to do it. I'm thinking I should simply not declare getValue in the Base class and then just make sure each derived class implements their version of it.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
Daniel Goldfarb
  • 6,937
  • 5
  • 29
  • 61
  • Have a look at templates, mixins and the CRTP, these would open a whole world of possibilities beyond dynamic polymorphism. Something like `void getValue() = 0;` absolutely makes zero sense BTW. – πάντα ῥεῖ Aug 23 '18 at 16:36
  • @ R Sahu- thanks for fixing my typos! – Daniel Goldfarb Aug 23 '18 at 16:39
  • @πάντα ῥεῖ -- thanks. reading up on CRTP now. Looks like that may be just what I needed in this case. – Daniel Goldfarb Aug 23 '18 at 16:43
  • Re: "I should simply not declare getValue in the Base class" -- maybe. You're talking here about writing code; the underlying problem is one of design. What is it that you're trying to do? Why do you need different signatures in the derived classes, and what connection, if any, do those functions have to the one declared in the base class? – Pete Becker Aug 23 '18 at 16:50
  • @DanielGoldfarb imagine this possible how would you use this functionality, have you though about it? – Slava Aug 23 '18 at 16:53
  • And no CRTP will not solve your problem. – Slava Aug 23 '18 at 17:06
  • This is an XY problem. "In order to do X I need Y". However, it is undoubtedly the case that X is not the right thing to be doing. What, logically are you trying to achieve? In english? – Richard Hodges Aug 23 '18 at 20:43

2 Answers2

5

If use of CRTP would work for you, you can use:

#include <string>

template <typename TypeSelector>
class Base {
  public:
     using type = typename TypeSelector::type;
     virtual void getValue(type t) = 0;
};

struct TypeSelector_A {
   using type = std::string&;
};

class Derived_A : public Base<TypeSelector_A> {
   public:
      void getValue(std::string& s) { /* Add real implementation */ }
};

struct TypeSelector_B {
   using type = int*;
};

class Derived_B : public Base<TypeSelector_B> {
   public:
      void getValue(int* j) { /* Add real implementation */ }
};

int main()
{
   Derived_A a;
   Derived_B b;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    Why would you need inheritance and virtual function in this case when it cannot be really used? – Slava Aug 23 '18 at 16:50
  • @Slava, That questions CRTP as a fundamental, viable, concept. – R Sahu Aug 23 '18 at 16:53
  • I do not think so, I think your example is abuse of CRTP. – Slava Aug 23 '18 at 16:54
  • Why use an intermediate selector class? Why not simply use `template class Base { public: virtual void getValue(type t) = 0; };` – vdavid Aug 23 '18 at 16:55
  • @Slava, it will be if `Base` does not have anything else in it. If `Base` has additional code that uses `getValue`, then it is a legitimate use of CRTP. – R Sahu Aug 23 '18 at 16:57
  • @vdavid so CRTP concept can be brought here and for all doubts RSahu can task you "are you questioning fundamental concept?" – Slava Aug 23 '18 at 16:57
  • @vdavid, that's a possibility too. – R Sahu Aug 23 '18 at 17:00
1

But what I really want to do is something like this: Force each derived class to implement getValue() but each with a different signature

The whole point of having virtual function (abstract or not) is that you can use it with pointer or reference to the base class which means you would use signature of the function from the base class. With that having what you want is completely useless. What you want can be implemented by returning std::variant or std::any with every virtual function in tree so keeping signature the same.

You should think how would you use such concept if it would be possible. If you think somethink like this:

void foo( Base *b ) {
    if( auto *d = dynamic_cast<Derived_A *>( b ) ) {
       std::string str;
       d->getValue( str );
       ...
    }
    if( auto *d = dynamic_cast<Derived_B *>( b ) ) {
       int i = 0;
       d->getValue( &i );
       ...
    }
}

then getValue() does not need to be virtual, you only need vritual destrictor in Base. But this is considered bad design.

Slava
  • 43,454
  • 1
  • 47
  • 90