假设我在C ++中有以下类层次结构:
class Base;
class Derived1 : public Base;
class Derived2 : public Base;
class ParamType;
class DerivedParamType1 : public ParamType;
class DerivedParamType2 : public ParamType;
我希望在func(ParamType)
中定义的多态函数Base
为DerivedParamType1
采用Derived1
类型的参数,并为DerivedParamType2
类型的参数Derived2
。
如果可能,如果没有指针,如何做到这一点?
答案 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)
然后你可以消除其中一个跳跃。