[英]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.