【问题标题】:In C++, how do I determine if a class is the last class/child in an inheritance chain? ie on the opposite end of the base class在 C++ 中,如何确定一个类是否是继承链中的最后一个类/子类?即在基类的另一端
【发布时间】:2015-10-20 20:31:06
【问题描述】:

我在简明扼要地表达这个问题时遇到了问题,但基本上一个类中的一个函数可能是继承链中的最后一个类,也可能不是。在这个函数内部,如果类级函数是继承链中的最后一个,则将调用第二个函数。展示我在说什么比解释它容易得多,所以:

假设我有 Z 课。

Z 派生自 Y,Y 派生自 X,X 派生自 W。

所有类都有一个名为 Execute() 的虚函数。

Z.Execute() 要求 Y.Execute() 结束,这就要求 X.Execute() 结束,这要求 W.Execute() 结束。

因此,Z 的 Execute() 函数如下所示:

void Z::Execute(void)
{
   Y::Execute();

   // do Z's stuff!
   return;
}

同样,Y 的 Execute() 函数看起来像:

void Y::Execute(void)
{
   X::Execute();

   // do Y's stuff!
   return;
}

在继承链中以此类推。

但是 Y、X 和 W 都是抽象的,因此每个都可以被实例化,并且可能是也可能不是继承链中的最后一个类。

这是我需要知道的。最后的 Execute() 需要调用 DoThisAtEndOfExecute()。 DoThisAtEndOfExecute() 需要在类内部调用,即。它不会公开。

所以不能在 X 的 Execute() 中,因为如果类是 Y 的话,会调用得太早。它不能在 Y 的 Execute() 中,因为类可能是 Z。它不能在 Z 的 Execute() 中,因为如果类是 Y、X 或 W,则永远不会调用该函数。

那么有没有办法让一个类判断它是否是从 FROM 继承的呢?基本上,相当于:

if (!IAmTheParentOfSomething)
   DoThisAtEndOfExecute();

这是怎么做到的?我承认更简单的方法是让包含该类的函数执行:

X.Execute();
X.DoThisAtEndOfExecute();

但这并不是这段代码的真正选择。

【问题讨论】:

  • 可以保护成员函数。这样,它只对声明类及其派生类可用。就像你想要的那样,它介于公共和私人之间。

标签: c++ class inheritance children


【解决方案1】:

我认为如果将 Execute 拆分为非虚拟部分和虚拟部分,可以实现您想要的。前者将运行后者,然后调用DoThisAtEndOfExecute。像这样:

class X
{
public:
    void Execute()
    {
        ExecuteImpl(); //That one's virtual, the derived classes override it
        DoThisAtEndOfExecute();
    }

protected:
    virtual void ExecuteImpl()
    {
        //Whatever was in the legacy Execute
    }
}

Y 和 Z 覆盖 ExecuteImpl() 并调用基础。这样,DoThisAtEndOfExecute() 在 ExecuteImpl() 的最派生版本完成后运行,无需了解实际类。

【讨论】:

  • 我将 Execute() 设为 public 和 ExecuteImpl() protected 以允许堆叠。
  • 又名“模板方法”。
【解决方案2】:

一种可能的解决方案是向 Execute 添加一个默认参数,然后在后续调用中将该参数更改为其他值。

class X{
    void Execute(bool isFinal = true);
};
//and so on.

void Z::Execute(bool isFinal)
{
   Y::Execute(false);
   // do Z's stuff!
   if(isFinal){
       // You're up!
   }
   return;
}

void Y::Execute(bool isFinal)
{
   X::Execute(false);

   // do Y's stuff!
   if(isFinal){
       // Y is the last class in this chain.
   }
   return;
}

这样,每当代码调用对象的Execute 方法(没有参数),然后该方法将被告知一些外部代码正在执行它。如果您愿意,这还允许您通过将false 传递给方法来防止执行所述终止代码。

【讨论】:

  • 我已经想到了。我希望有一些实际的内置功能。
  • 不幸的是,没有办法知道一个类本身是否离基类最远(至少我无法理解)。但是,总有一种方法可以让对象知道它是否被外部调用(如您所知)。我想知道您是否在这里遇到了 X-Y 问题?
【解决方案3】:

移动 //do ... 的东西怎么样!变成一个单独的函数?

class W
{
protected:
  void Stuff() { /*...*/ };
  void Finalize() { /*...*/ };
public:
  virtual ~W() {}
  virtual void Execute() { /*...*/ };
};
class X : public W
{
protected:
  void Stuff() { 
    // X Stuff
    W::Stuff();
  };
public:
  virtual ~X() {}
  virtual void Execute() { 
    X::Stuff();
    W::Finalize();
  };
};

class Y : public X
{
  void Stuff() {
    // Y Stuff
    X::Stuff();
  };
public:
  virtual ~Y() {}
  virtual void Execute() {
    Y::Stuff();
    W::Finalize();
  };
};

【讨论】:

  • 我认为你和 Seva Alekseyev 的想法相似。
  • 这里的区别是Execute() 而不是Stuff() 是虚拟的,你能解释一下你为什么走这条路吗?毕竟Execute() 的所有不同实现基本上都避免了虚拟查找,但除此之外做同样的事情......
  • 我只是为了说明分离以实现所需的行为。恕我直言,非虚拟界面更可取。
猜你喜欢
  • 1970-01-01
  • 2020-11-16
  • 2014-10-08
  • 2011-01-10
  • 2016-01-13
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 2012-04-29
相关资源
最近更新 更多