簡體   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