具有来自类层次结构的参数的多态函数

时间:2010-04-13 08:44:26

标签: c++ polymorphism

假设我在C ++中有以下类层次结构:

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


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

我希望在func(ParamType)中定义的多态函数BaseDerivedParamType1采用Derived1类型的参数,并为DerivedParamType2类型的参数Derived2

如果可能,如果没有指针,如何做到这一点?

6 个答案:

答案 0 :(得分:2)

您正在寻找协变参数。这在C ++中是不可能的,它只支持协变返回类型。

这不仅仅是语言上的遗漏。你想要做的事实际上没有意义。例如,想象一下,您可以定义以下设置:

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

答案 1 :(得分:2)

你不能让Base :: func采用不同的参数,具体取决于继承它的类。你需要改变一些东西。

您可以使用ParamType并使用您喜欢的任何机制处理意外参数(例如,抛出异常或返回错误代码而不是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 :(得分:2)

这违背了多态的目的;如果Base提供了一个函数Base::func(const ParamType&),那么相同的函数(或它的覆盖)需要在Derived1中接受const ParamType&。您可以为专属于func的{​​{1}}提供重载。

与您正在寻找的最接近的是提供这样的专门重载,然后将const DerivedParamType1&设为私有。但请注意,这会破坏多态性。多态性的全部意义在于,如果你可以在基类型上调用函数,那么你可以在从它继承的任何类上调用相同的函数(具有相同的参数),显然不是这种情况。

答案 3 :(得分:1)

这称为double dispatch,虽然这必须通过指向基类的指针来完成,这就是多态性的工作原理。在C ++中,不直接支持双重调度,因此涉及一些工作。

答案 4 :(得分: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&);
};

答案 5 :(得分:0)

正如stefaanv所说,这可以通过双重调度和一些额外的管道来实现:

#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;
}

请注意,当您要求Base::func(ParamType)呼叫Derived1::func(DerivedParamType1)时,实际上有3次跳转(发送)。如果你对以下任何一个感到满意:

Base::func(ParamType)来电DerivedParamType1::func(Derived1)

ParamType::func(Base)来电Derived1::func(DerivedParamType1)

然后你可以消除其中一个跳跃。