[英]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;
};
一種選擇是使燃料類型也成為一個層次結構( Kerosene
和Petrol
都繼承了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.