c++ - 我是否在特定情况下证明多重继承是合理的?

标签 c++ inheritance multiple-inheritance

目前,我有以下管理不同类型变量的类:

class Variable;
class Number : public Variable;
class Boolean : public Variable;
class RealNumber : public Number;
class IntegerNumber : public Number;

这是一个经典的继承树,而且效果很好。我管理 Number* 的 vector Boolean* 的实例和 vector 实例。

我想添加另一种类型的变量:具有特定行为但具有相似接口(interface)的“虚拟变量”。然后,我想使用“虚拟数字” vector 和“虚拟 bool 值” vector 。

第一个解决方案是在 Variable 中添加一个标志, 但我更喜欢编译安全和管理 std::vector<VirtualResponse*>std::vector<VirtualBoolean*>为了保证变量在 vector 中是虚拟的。

然后,我想也许我处于多重继承合理的特定情况下,但我是多重继承的新手。 您如何看待这种类(class)?

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;
}

最佳答案

多重继承旨在通过确保 separation of concerns 来支持简洁的设计.所以可以说是天经地义。

如果不了解更多的原因和限制,就很难就最好的类设计提出建议。但有些问题可能对您有所帮助。

它从以下行开始:

    class VirtualVariable : public virtual Variable;

1)是否需要虚继承?

在你来到虚拟继承之前,多重继承是非常简单和有趣的。这意味着对于从 VirtualVariable 多次继承的类,所有 VirtualVariable 子对象实例将共享一个 Variable 基础对象。有关更多信息,请阅读 diamond problem .

在您的设计中,您可能需要它用于 Variable 的每个继承(包括非“虚拟”的)以避免有多个 Variable 子对象,其中你真的应该只有一个。其他继承不需要它。

此虚拟继承将要求您为每个构造函数显式初始化您的虚拟基础。

2) VariableVirtualVariable 之间的真正关系是什么?

根据您的解释,我了解到“虚拟”概念独立于“变量”概念。另一方面,在您的代码中,您假装 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 作为模板参数,而是提供一个实用程序类作为参数,该类封装了一系列行为。

编辑:供您编​​辑

解决方案 2 和 3 应该能够完美地实现您的意图。

我在这里张贴了一个 online demo 解决方案 2 的多态性,以演示您可以轻松混合“虚拟”和非“虚拟”元素。它定义了一个函数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()) ... 强烈建议您应该使用多态性。

关于c++ - 我是否在特定情况下证明多重继承是合理的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29920988/

相关文章:

perl - 如果已经有 'use'语句,是否需要使用 'use base'

objective-c - 从父类(super class)中调用子类的方法

c++ - 继承自具有相同成员的两个 parent

c++ - 当基类为一个方法共享相同的名称时,多重继承 C++ 有一些限制吗?

c++ - 虚拟继承、显式实例化——返回派生类引用/指针(协变类型)

c++ - 获取有关 X11 中鼠标光标最近显示器的信息

c++ - 读取和写入进程 I/O?

c++ - 使用 fscanf 读取字符串

scala - 带参数扩展类

c++ - googlemock 框架不适用于虚拟继承