Polymorphic functions with parameters from the class hierarchy

Let's say I have the following class hierarchy in C ++:

class Base;
class Derived1 : public Base;
class Derived2 : public Base;


class ParamType;
class DerivedParamType1 : public ParamType;
class DerivedParamType2 : public ParamType;

And I want the polymorphic function func(ParamType)defined in Baseto take a type parameter DerivedParamType1for Derived1and a type parameter DerivedParamType2for Derived2.

How can this be done without pointers, if possible?

+3
source share
6 answers

You cannot have Base :: func accept different parameters depending on which class inherits it. You need to change something.

You could force them to take ParamType and process the unexpected parameter with any mechanism convenient for you (for example, throw an exception or return an error code instead of void):

struct ParamType;
struct Base {
  void func(ParamType&);
}
struct Derived1 : Base {};
//...

, :

struct ParamType;
struct DerivedParamType1 : ParamType {};
struct DerivedParamType2 : ParamType {};

template<class ParamT>
struct Base {
  void func(ParamT&);
};
struct Derived1 : Base<DerivedParamType1> {};
struct Derived2 : Base<DerivedParamType2> {};

Derived1 Derived2 .

+2

. ++, .

. , , . , , :

class Decoder { virtual void decode(Stream*); };
class Base64Decoder { void decode(Base64Stream*); };
class GZipDecoder { void decode(GZipStream*); };
...
Decoder* d = new Base64Decoder;
d.decode(new GZipStream("file.gz"));

Decoder::decode() Stream, . , , Base64Decoder::decode GZipStream.

+2

; Base Base::func(const ParamType&), ( ) const ParamType& Derived1. func, const DerivedParamType1&.

, , - ​​ , Derived1::func(const ParamType&) . , , . , , ( ) , .

+2

, , . ++ , .

+1

( ) , . reinterpret_cast - , , , .

, , , . , , , "" .

class Base
{
public:
   class ParamType { }

   void DoSomething(const ParamType&); // called by derived classes as necessary
};

class Derived1 : public Base
{
public:
   class DerivedParamType1 : public ParamType { }

   void DoSomething(const DerivedParamType1&);
};

class Derived2 : public Base
{
public:
   class DerivedParamType2 : public ParamType { }

   void DoSomething(const DerivedParamType2&);
};
+1
source

As Stefaan says, this can be achieved with double dispatch with additional fixtures:

#include <iostream>

class Derived1;
class Derived2;

class ParamType
{
public:
    virtual void invertFunc (const Derived1& deriv) const = 0;
    virtual void invertFunc (const Derived2& deriv) const = 0;
};

class DerivedParamType1;
class DerivedParamType2;

class Base
{
public:
    virtual void func (const ParamType& param) const = 0;

    virtual void func (const DerivedParamType1& param) const
    {
        throw std::runtime_error ("Can not accept DerivedParamType1");
    }

    virtual void func (const DerivedParamType2& param) const
    {
        throw std::runtime_error ("Can not accept DerivedParamType2");
    }
};

class Derived1 : public Base
{
public:
    void func (const ParamType& param) const
    {
        param.invertFunc (*this);
    }

    void func (const DerivedParamType1& param) const
    {
        std::cout << "Derived1::func (DerivedParamType1)" << std::endl;
    }
};

class Derived2 : public Base
{
public:
    void func (const ParamType& param) const
    {
        param.invertFunc (*this);
    }

    void func (const DerivedParamType2& param) const
    {
        std::cout << "Derived2::func (DerivedParamType2)" << std::endl;
    }
};

class DerivedParamType1 : public ParamType
{
public:
    void invertFunc (const Derived1& deriv) const
    {
        deriv.func (*this);
    }

    void invertFunc (const Derived2& deriv) const
    {
        deriv.func (*this);
    }
};

class DerivedParamType2 : public ParamType
{
public:
    void invertFunc (const Derived1& deriv) const
    {
        deriv.func (*this);
    }

    void invertFunc (const Derived2& deriv) const
    {
        deriv.func (*this);
    }
};


int main (int argc, char* argv[])
{
    ParamType* paramType = new DerivedParamType1;
    Base* deriv = new Derived1;

    deriv->func (*paramType);

    return 0;
}

Please note that there are actually three jumps (departures) when you asked to Base::func(ParamType)call Derived1::func(DerivedParamType1). If you are satisfied either:

Base::func(ParamType) causes DerivedParamType1::func(Derived1)

or

ParamType::func(Base) causes Derived1::func(DerivedParamType1)

then you can eliminate one of the jumps.

0
source

Source: https://habr.com/ru/post/1740890/


All Articles