如何确保虚拟方法调用一直传播到基类? [英] How to ensure that virtual method calls get propagated all the way to the base class?

查看:146
本文介绍了如何确保虚拟方法调用一直传播到基类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类层次结构中的一个常见错误是将基类中的方法指定为虚拟,以便继承链中的所有重写可以完成某些工作,并且忘记传播调用

One very common mistake with class hierarchies is to specify a method in a base class as being virtual, in order for all overrides in the inheritance chain to do some work, and forgetting to propagate the call on to base implementations.

class Container
{
public:
  virtual void PrepareForInsertion(ObjectToInsert* pObject)
  {
    // Nothing to do here
  }
};

class SpecializedContainer : public Container
{
protected:
  virtual void PrepareForInsertion(ObjectToInsert* pObject)
  {
    // Set some property of pObject and pass on.
    Container::PrepareForInsertion(pObject);
  }
};

class MoreSpecializedContainer : public SpecializedContainer
{
protected:
  virtual void PrepareForInsertion(ObjectToInsert* pObject)
  {
    // Oops, forgot to propagate!
  }
};

我的问题是:有一个很好的方式/模式,在调用链结束时调用?

我知道有两种方法可以做到这一点。

I know of two methods to do this.

您可以使用成员变量作为标志,将其设置为虚拟方法的基本实现中的正确值,然后检查其值调用。这需要使用公共非虚拟方法作为客户端的接口,并使虚拟方法受保护(这实际上是一件好事),但它需要使用专门为此目的的成员变量(这需要如果虚拟方法必须为const,则为可变的)。

You can use a member variable as a flag, set it to the correct value in the base implementation of the virtual method, and check its value after the call. This requires to use a public non-virtual method as interface for the clients, and making the virtual method protected (which is actually a good thing to do), but it requires the use of a member variable specifically for this purpose (which needs to be mutable if the virtual method must be const).

class Container
{
public:
  void PrepareForInsertion(ObjectToInsert* pObject)
  {
    m_callChainCorrect = false;
    PrepareForInsertionImpl(pObject);
    assert(m_callChainCorrect);
  }

protected:
  virtual void PrepareForInsertionImpl(ObjectToInsert* pObject)
  {
    m_callChainCorrect = true;
  }

private:
  bool m_callChainCorrect;
};

class SpecializedContainer : public Container
{
protected:
  virtual void PrepareForInsertionImpl(ObjectToInsert* pObject)
  {
    // Do something and pass on
    Container::PrepareForInsertionImpl(pObject);
  }
};



方法2



它是用不透明的cookie参数替换成员变量,并做同样的事情:

Method 2

The other way to do it is to replace the member variable with an opaque "cookie" parameter and do the same thing:

class Container
{
public:
  void PrepareForInsertion(ObjectToInsert* pObject)
  {
    bool callChainCorrect = false;
    PrepareForInsertionImpl(pObject, &callChainCorrect);
    assert(callChainCorrect);
  }

protected:
  virtual void PrepareForInsertionImpl(ObjectToInsert* pObject, void* pCookie)
  {
    *reinrepret_cast<bool*>(pCookie) = true;
  }
};

class SpecializedContainer : public Container
{
protected:
  virtual void PrepareForInsertionImpl(ObjectToInsert* pObject, void* pCookie)
  {
    // Do something and pass on
    Container::PrepareForInsertionImpl(pObject, pCookie);
  }
};

这种方法不如我认为的第一种方法,但它避免使用专用

This approach is inferior to the first one in my opinion, but it does avoid the use of a dedicated member variable.

还有什么其他可能性?

推荐答案

我们提出了一些聪明的方法来做到这一点,在(如你所知)成本的膨胀类和添加代码不是对象的责任,而不是程序员的缺陷。

You've come up with some clever ways to do this, at (as you acknowledge) the cost of bloating the class and adding code that addresses not the object's responsibilities but programmer deficiences.

真正的答案不是在运行时这样做。这是一个程序员错误,而不是运行时错误。

The real answer is not to do this at runtime. This is a programmer error, not a runtime error.

在编译时执行:使用语言构造,如果语言支持它,或使用Pattern强制它,例如,模板方法),或者让你的编译依赖于测试传递,并设置测试来强制它。

Do it at compile time: use a language construct if the language supports it, or use a Pattern the enforces it (e.g,, Template Method), or make your compilation dependent on tests passing, and set up tests to enforce it.

传播导致派生类失败,让它失败,并带有一个异常消息,通知派生类的作者他未能正确使用基类。

Or, if failing to propagate causes the derived class to fail, let it fail, with an exception message that informs the author of the derived class that he failed to use the base class correctly.

这篇关于如何确保虚拟方法调用一直传播到基类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆