C++ 具有类层次结构参数的多态函数

C++ 具有类层次结构参数的多态函数,c++,polymorphism,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),在Base中定义,用于derivedparmtype

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

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


class ParamType;
class DerivedParamType1 : public ParamType;
class DerivedParamType2 : public ParamType;
我想要一个多态函数,
func(ParamType)
,在
Base
中定义,用于
derivedparmtype1
类型的参数和
derivedparmtype2
类型的参数


如果可能的话,如果没有指针,这将如何实现?

您正在寻找协变参数。这在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()
接受任何
,因此最后一行是有效代码。如果虚拟函数规则允许您所需的,则会向
Base64Decoder::decode
传递一个
GZipStream

您不能让Base::func根据继承它的类采用不同的参数。你需要改变一些东西

您可以让它们都采用ParamType并使用您喜欢的任何机制处理意外参数(例如,抛出异常或返回错误代码而不是void):

或模板,以确定它们应采用的参数类型:

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

template<class ParamT>
struct Base {
  void func(ParamT&);
};
struct Derived1 : Base<DerivedParamType1> {};
struct Derived2 : Base<DerivedParamType2> {};
struct参数类型;
结构DerivedParamType1:ParamType{};
结构DerivedParamType2:ParamType{};
模板
结构基{
无效函数(参数&);
};
结构Derived1:Base{};
struct-Derived2:Base{};

对于第二种解决方案,Derived1和Derived2将不共享一个公共基,并且不能以多态方式使用。

这被调用,尽管这必须通过指向基类的指针来完成,但多态性就是这样工作的。在C++中,不直接支持双分派,因此有一些工作涉及。如果Base提供了一个函数
Base::func(const ParamType&)
,那么该函数(或其重写)需要接受Derived1中的
const ParamType&
。您可以为
func
提供重载,该重载在
const-DerivedParamType1&
上专用


最接近您所要寻找的是提供这样一个专门的重载,然后使
Derived1::func(const ParamType&)
private。但是,请注意,这会破坏多态性。多态性的全部要点是,如果您可以在基类型上调用函数,那么您可以在继承自它的任何类上调用相同的函数(使用相同的参数),这显然不是事实。

正如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;
}
#包括
派生类1;
派生类2;
类参数类型
{
公众:
虚空反转函数(常数Derived1&deriv)常数=0;
虚空反转函数(const-Derived2&deriv)const=0;
};
类别1;
类别2;
阶级基础
{
公众:
虚空函数(const-ParamType¶m)const=0;
虚空函数(常量DerivedParamType1¶m)常量
{
抛出std::runtime_错误(“无法接受DerivedParamType1”);
}
虚空函数(常量DerivedParamType2¶m)常量
{
抛出std::runtime_错误(“无法接受DerivedParamType2”);
}
};
类Derived1:公共基
{
公众:
无效函数(常量参数类型和参数)常量
{
param.invertFunc(*此参数);
}
无效函数(常量派生参数类型1和参数)常量
{
std::cout如果这些(运算符类和参数类型)是独立的概念,那么它们应该保持独立。重新解释\u 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&);
};

我承认
指针
有点麻烦。你认为多态性只有在使用指针时才会出现吗:/?我的意思是,我希望传递给函数的参数最好是一个对象或引用,而不是指针。理论上,重写函数需要一个兼容的签名,而不是完全相同的ACT,C++允许协变返回类型。但是,输入参数是相反的,而非const指针和引用是不变的。@本:我不确定你想指出的是什么。对于输入的参数,反变量参数满足LSP,尽管C++不允许。协变参数是无效的,甚至在理论上(它们必须只输出,而C++没有这个概念)。
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&);
};