繁体   English   中英

对具有不同数量参数的虚函数的多态调用

[英]Polymorphic call to virtual functions with varying number of arguments

是否可以使用虚函数实现下面演示的行为?
如果这不是处理多态的正确方法,那么在这个例子中正确的方法是什么?

class Base_
{
    float x;
    float y;
    float z;
public:
    Base_(float xx=0, float yy=0, float zz=0)
    {
        x = xx;
        y = yy;
        z = zz;
    }
   virtual void SetParemeters(what here?)=0; //Different number of arguments 
};

class Derived_1 :public Base_
{
    float r;
public:
    Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
    {
        r=rr;
    }
    virtual void SetParemeters(float v1) //Different number of arguments
    {
        r=v1;
    }
};

class Derived_2 :public Base_
{
    float k;
    float w;
public:
    Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
    {
        k=kk;
        w=ww;
    }
    virtual void SetParemeters(float v1, float v2) //Different number of arguments
    {
        k=v1;
        w=v2;
    }
};
int main()
{
    Derived_1 d1;
    Derived_2 d2;
    Base_ *ptr;

    ptr = &d1;
    ptr -> SetParemeters(one argument)

    ptr = &d2;
    ptr-> SetParemeters(one or two arguments) 

    return 0;
}

即使我设法实现了这一点,我怎么能在这里只设置第二个参数 (k):
ptr-> SetParemeters(one or two arguments)

我搜索了答案,但我只找到了特定场景的答案,这让我难以理解整件事。

是的,make Base_::SetParameters需要两个(可选)参数:

class Base_
{
// [...]
public:
   virtual void SetParemeters(float=0f, float=0f)=0;
};

Derived_1::SetParameters只是忽略第一个:

class Derived_1 :public Base_
{
    // [...]
    virtual void SetParemeters(float v1, float=0f)
    {
        r=v1;
    }
};

Derived_2需要他们两个

class Derived_2 :public Base_
{
    // [...]
    virtual void SetParemeters(float v1, float v2)
    {
        k=v1;
        w=v2;
    }
};

演示: https : //coliru.stacked-crooked.com/a/c528ffff005df5b9

但请注意,这显着降低了虚函数的兴趣......

Derived_1 d1;
Derived_2 d2;
Base_ *ptr;

ptr = &d1;
ptr->SetParameters(one argument)

ptr = &d2;
ptr->SetParameters(one or two arguments) 

这段代码的编写方式意味着您了解两件事:

  • 在第一次调用SetParameters()ptr指向Derived_1类型的对象
  • 在第二次调用时,它指向Derived_2类型的对象。

这反过来意味着您知道静态类型——事实上,由于不同的签名,您需要知道。

对于这种情况,动态多态不是正确的选择,因为它的前提是您可以使用统一访问(调用虚拟基方法)与不同的实现(覆盖的方法)对话。

因此,如果您在编译时掌握了这些知识,只需使用非虚拟方法调用即可。


但是,在类似的情况下,您可能实际上对在运行时支持不同的签名感兴趣,例如,如果您动态加载配置。 这是一个示例,其中不是number ,而是参数类型不同。

class Car : public Vehicle
{
    virtual void addFuel(const Petrol& f) override;
};

class Airplane : public Vehicle
{
    virtual void addFuel(const Kerosene& f) override;
};

那么基函数看起来如何呢?

class Vehicle
{ 
    virtual ~Vehicle() {} // don't forget this!
    virtual void addFuel(const /* which type? */& f) = 0;
};

一种选择是使燃料类型也成为一个层次结构( KerosenePetrol都继承了Fuel类):

class Vehicle
{ 
    virtual ~Vehicle() {}
    virtual void addFuel(const Fuel& f) = 0;
};

但是,在这种情况下,每个实现都需要依赖于它传递了正确的燃料这一事实,或者在运行时检查类型。

class Airplane : public Vehicle
{
    virtual void addFuel(const Fuel& f) override
    {
        if (auto* k = dynamic_cast<const Kerosene*>(&f))
        {
            // use concrete fuel
        }
    }
};

您可以使SetParameters成为可变参数函数,并将多态接口设为内部,以通用形式提供可写参数(此处作为指向它们的指针向量):

class Base_
{
    float x;
    float y;
    float z;
public:
    Base_(float xx=0, float yy=0, float zz=0)
    {
        x = xx;
        y = yy;
        z = zz;
    }

    virtual std::vector<float*> getAllExtraParameters() = 0;

    template<class ... Ts>
    void SetExtraParameters(Ts&& ... ts)
    {
        auto extras = getAllExtraParameters();
        if (sizeof...(ts) > extras.size())
          throw std::runtime_error("Too many parameters given!");

        // Fold expression - could be implemented differently in C++ < 17.
        int index = 0;
        ((*extras[index++] = ts), ...);
    }
};


class Derived_1 :public Base_
{
    float r;
public:
    Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
    {
        r=rr;
    }

    std::vector<float*> getAllExtraParameters() override
    {
        return { &r };
    }
};

class Derived_2 :public Base_
{
public:
    float k;
    float w;

    Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
    {
        k=kk;
        w=ww;
    }

    std::vector<float*> getAllExtraParameters() override
    {
        return { &k, &w };
    }
};

演示和测试: https : //godbolt.org/z/ofXnuH

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM