我是否在特定情况下证明多重继承是合理的?
Am I in a specific case justifying multiple inheritance?
目前,我有以下 类 管理不同种类的变量:
class Variable;
class Number : public Variable;
class Boolean : public Variable;
class RealNumber : public Number;
class IntegerNumber : public Number;
这是一个经典的继承树,效果很好。我管理 Number*
个实例的向量和 Boolean*
个实例的向量。
我想添加另一种类型的变量:'virtual variable' 具有特定的行为但具有相似的界面。然后,我想使用 'virtual numbers' 的向量和 'virtual booleans' 的向量。
第一个解决方案是在 Variable
中添加一个标志,但我更喜欢编译安全并管理 std::vector<VirtualResponse*>
和 std::vector<VirtualBoolean*>
以保证变量在矢量。
然后,我想也许我处于多重继承合理的特定情况下,但我是多重继承的新手。 你怎么看待这种类?
class VirtualVariable : public virtual Variable;
class VirtualNumber : public virtual Number, public virtual VirtualVariable;
class VirtualBoolean : public virtual Boolean, public virtual VirtualVariable;
class VirtualRealNumber : public virtual RealNumber, public virtual VirtualNumber;
class VirtualIntegerNumber : public virtual IntegerNumber, public virtual VirtualVariable;
这是一种经典的方法吗?会不会是陷阱?我是否滥用了 virtual
关键字?
编辑:我想做的事的例子:
void my_function(const std::vector<SpecItem>& spec)
{
// First : create the description from the spec
std::vector<Number*> descr;
std::vector<VirtualNumber*> virt_descr;
for(unsigned long int i = 0; i < spec.size(); ++i)
{
if(spec[i].isNumber())
if(spec[i].isReal())
{
double lower_bound = spec[i].lowerBound();
double upper_bound = spec[i].upperBound();
if(spec[i].isVirtual())
{
std::string formula = spec[i].formula();
virt_descr.push_back(new VirtualRealNumber(lower_bound,upper_bound,formula));
}
else
descr.push_back(new RealNumber(lower_bound,upper_bound));
}
else if(spec[i].isInteger())
{
long int lower_bound = ceil(spec[i].lowerBound());
long int upper_bound = floor(spec[i].upperBound());
if(spec[i].isVirtual())
{
std::string formula = spec[i].formula();
virt_descr.push_back(new VirtualIntegerNumber(lower_bound,upper_bound,formula));
}
else
descr.push_back(new IntegerNumber(lower_bound,upper_bound));
}
}
// Now, descr is a vector of Number*, virt_descr is a vector of VirtualNumber*
// Second step : assign values to the numbers
std::vector<double> values;
for(unsigned long int i = 0; i < descr.size(); ++i)
{
double new_value = (descr[i]->lowerBound() + descr[i]->upperBound()) / 2.0;
values.push_back(descr[i]->adjust(new_value));
}
// Third step : evaluate virtual numbers
std::vector<double> virt_values;
for(unsigned long int i = 0; i < virt_descr.size(); ++i)
{
double new_value = virt_descr[i]->evaluate(values);
values.push_back(descr[i]->adjust(new_value));
}
return 0;
}
我尽量避免多重继承。
听起来您想要一个对象,它的行为类似于基础对象,但针对特定情况进行了更改。听起来像 class 规范。我不确定您的目标是什么,但也许您可以将您的设计更改为 class 层次结构模型。要实现这一点,请将所有特定代码放在单独的函数中,然后在基础 class.
中调用
class Number : public Variable
{
...
protected:
virtual void functionWithSpecialUsage() { // Empty in base class, used by inheritance only };
}
class VirtualNumber : public Number
{
...
protected:
void functionWithSpecialUsage() { // Add class specific behavior here };
}
多重继承旨在通过确保 separation of concerns 来支持简洁的设计。所以可以说是天经地义。
在不了解更多原因和限制的情况下,很难就最好的 class 设计提出建议。但有些问题可能对您有所帮助。
它从以下行开始:
class VirtualVariable : public virtual Variable;
1)是否需要虚拟继承?
多继承真的很简单有趣,直到你来到虚拟继承。这意味着对于从 VirtualVariable
多次继承的 class,所有 VirtualVariable
子对象实例将共享一个 Variable
基础对象。有关详细信息,请阅读 diamond problem。
在您的设计中,您可能需要为 Variable
的每个继承(包括非 "Virtual" 的继承)以避免拥有多个 Variable
子对象,而您真正应该只有一个。其他继承不需要它。
此虚拟继承将要求您为每个构造函数显式初始化您的虚拟基础。
2) Variable
和 VirtualVariable
之间的真正关系是什么?
根据您的解释,我了解到 "Virtuality" 概念独立于 "Variable" 概念。另一方面,在您的代码中,您假设 VirtualVariable
是 Variable
。
如果它是独立的东西,你应该保持它的独立性。这将是更好的关注点分离。好消息是你不再需要虚拟继承:
class Virtuality;
class VirtualVariable : public Variable, public Virtuality;
class VirtualNumber : public Number, public Virtuality;
class VirtualBoolean : public Boolean, public Virtuality;
class VirtualRealNumber : public RealNumber, public Virtuality;
class VirtualIntegerNumber : public IntegerNumber, public Virtuality;
3) 你看过模板了吗?
你说:
A first solution is adding a flag in Variable, but I prefer the
compilation security and manage
如果只是为了编译类型检查,可以使用模板:
template <bool isvirtual>
Variable { ...};
template <bool isvirtual>
class Number : Variable<isvirtual> { ...};
...
std::vector<Number<true>*> v;
对于比变量更复杂的事物,您可以使用基于策略的设计。粗略地说,不是提供 bool 作为模板参数,而是提供实用程序 class 作为参数,class 封装了一系列行为。
编辑:供您编辑
解决方案 2 和 3 应该完全能够实现您的意图。
我在这里发布了解决方案 2 的 online demo 和多态性来演示混合 "Virtual" 和非 "Virtual" 元素是多么容易.它定义了一个函数IntegerNumber add (IntegerNumber &a, IntegerNumber&b);
,并在这个场景中使用它:
IntegerNumber n(27); // number with an inital value
VirtualIntegerNumber k; // value will be calculated from some formula
add (n, k); // ok, my demo just displays the value of each parameter ;-)
*顺便说一句,我认为您代码中的构造 if (isxxx())... if (isyyy()) ...
强烈建议您应该使用多态性。
目前,我有以下 类 管理不同种类的变量:
class Variable;
class Number : public Variable;
class Boolean : public Variable;
class RealNumber : public Number;
class IntegerNumber : public Number;
这是一个经典的继承树,效果很好。我管理 Number*
个实例的向量和 Boolean*
个实例的向量。
我想添加另一种类型的变量:'virtual variable' 具有特定的行为但具有相似的界面。然后,我想使用 'virtual numbers' 的向量和 'virtual booleans' 的向量。
第一个解决方案是在 Variable
中添加一个标志,但我更喜欢编译安全并管理 std::vector<VirtualResponse*>
和 std::vector<VirtualBoolean*>
以保证变量在矢量。
然后,我想也许我处于多重继承合理的特定情况下,但我是多重继承的新手。 你怎么看待这种类?
class VirtualVariable : public virtual Variable;
class VirtualNumber : public virtual Number, public virtual VirtualVariable;
class VirtualBoolean : public virtual Boolean, public virtual VirtualVariable;
class VirtualRealNumber : public virtual RealNumber, public virtual VirtualNumber;
class VirtualIntegerNumber : public virtual IntegerNumber, public virtual VirtualVariable;
这是一种经典的方法吗?会不会是陷阱?我是否滥用了 virtual
关键字?
编辑:我想做的事的例子:
void my_function(const std::vector<SpecItem>& spec)
{
// First : create the description from the spec
std::vector<Number*> descr;
std::vector<VirtualNumber*> virt_descr;
for(unsigned long int i = 0; i < spec.size(); ++i)
{
if(spec[i].isNumber())
if(spec[i].isReal())
{
double lower_bound = spec[i].lowerBound();
double upper_bound = spec[i].upperBound();
if(spec[i].isVirtual())
{
std::string formula = spec[i].formula();
virt_descr.push_back(new VirtualRealNumber(lower_bound,upper_bound,formula));
}
else
descr.push_back(new RealNumber(lower_bound,upper_bound));
}
else if(spec[i].isInteger())
{
long int lower_bound = ceil(spec[i].lowerBound());
long int upper_bound = floor(spec[i].upperBound());
if(spec[i].isVirtual())
{
std::string formula = spec[i].formula();
virt_descr.push_back(new VirtualIntegerNumber(lower_bound,upper_bound,formula));
}
else
descr.push_back(new IntegerNumber(lower_bound,upper_bound));
}
}
// Now, descr is a vector of Number*, virt_descr is a vector of VirtualNumber*
// Second step : assign values to the numbers
std::vector<double> values;
for(unsigned long int i = 0; i < descr.size(); ++i)
{
double new_value = (descr[i]->lowerBound() + descr[i]->upperBound()) / 2.0;
values.push_back(descr[i]->adjust(new_value));
}
// Third step : evaluate virtual numbers
std::vector<double> virt_values;
for(unsigned long int i = 0; i < virt_descr.size(); ++i)
{
double new_value = virt_descr[i]->evaluate(values);
values.push_back(descr[i]->adjust(new_value));
}
return 0;
}
我尽量避免多重继承。 听起来您想要一个对象,它的行为类似于基础对象,但针对特定情况进行了更改。听起来像 class 规范。我不确定您的目标是什么,但也许您可以将您的设计更改为 class 层次结构模型。要实现这一点,请将所有特定代码放在单独的函数中,然后在基础 class.
中调用class Number : public Variable
{
...
protected:
virtual void functionWithSpecialUsage() { // Empty in base class, used by inheritance only };
}
class VirtualNumber : public Number
{
...
protected:
void functionWithSpecialUsage() { // Add class specific behavior here };
}
多重继承旨在通过确保 separation of concerns 来支持简洁的设计。所以可以说是天经地义。
在不了解更多原因和限制的情况下,很难就最好的 class 设计提出建议。但有些问题可能对您有所帮助。
它从以下行开始:
class VirtualVariable : public virtual Variable;
1)是否需要虚拟继承?
多继承真的很简单有趣,直到你来到虚拟继承。这意味着对于从 VirtualVariable
多次继承的 class,所有 VirtualVariable
子对象实例将共享一个 Variable
基础对象。有关详细信息,请阅读 diamond problem。
在您的设计中,您可能需要为 Variable
的每个继承(包括非 "Virtual" 的继承)以避免拥有多个 Variable
子对象,而您真正应该只有一个。其他继承不需要它。
此虚拟继承将要求您为每个构造函数显式初始化您的虚拟基础。
2) Variable
和 VirtualVariable
之间的真正关系是什么?
根据您的解释,我了解到 "Virtuality" 概念独立于 "Variable" 概念。另一方面,在您的代码中,您假设 VirtualVariable
是 Variable
。
如果它是独立的东西,你应该保持它的独立性。这将是更好的关注点分离。好消息是你不再需要虚拟继承:
class Virtuality;
class VirtualVariable : public Variable, public Virtuality;
class VirtualNumber : public Number, public Virtuality;
class VirtualBoolean : public Boolean, public Virtuality;
class VirtualRealNumber : public RealNumber, public Virtuality;
class VirtualIntegerNumber : public IntegerNumber, public Virtuality;
3) 你看过模板了吗?
你说:
A first solution is adding a flag in Variable, but I prefer the compilation security and manage
如果只是为了编译类型检查,可以使用模板:
template <bool isvirtual>
Variable { ...};
template <bool isvirtual>
class Number : Variable<isvirtual> { ...};
...
std::vector<Number<true>*> v;
对于比变量更复杂的事物,您可以使用基于策略的设计。粗略地说,不是提供 bool 作为模板参数,而是提供实用程序 class 作为参数,class 封装了一系列行为。
编辑:供您编辑
解决方案 2 和 3 应该完全能够实现您的意图。
我在这里发布了解决方案 2 的 online demo 和多态性来演示混合 "Virtual" 和非 "Virtual" 元素是多么容易.它定义了一个函数IntegerNumber add (IntegerNumber &a, IntegerNumber&b);
,并在这个场景中使用它:
IntegerNumber n(27); // number with an inital value
VirtualIntegerNumber k; // value will be calculated from some formula
add (n, k); // ok, my demo just displays the value of each parameter ;-)
*顺便说一句,我认为您代码中的构造 if (isxxx())... if (isyyy()) ...
强烈建议您应该使用多态性。