gpt4 book ai didi

c++ - 如何确保虚方法调用一直传播到基类?

转载 作者:IT老高 更新时间:2023-10-28 22:32:04 27 4
gpt4 key购买 nike

类层次结构的一个非常常见的错误是将基类中的方法指定为虚拟方法,以便继承链中的所有覆盖做一些工作,而忘记传播调用到基础实现。

示例场景

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

我的问题是:有没有一种好的方法/模式来确保始终在调用链的末尾调用基本实现?

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

方法一

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

方法二

另一种方法是用不透明的“cookie”参数替换成员变量并做同样的事情:

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

在我看来,这种方法不如第一种,但确实避免了使用专用成员变量。

还有哪些可能?

最佳答案

您已经想出了一些巧妙的方法来做到这一点,但(正如您所承认的)膨胀类和添加的代码不是解决对象的职责而是解决程序员的缺陷。

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

在编译时执行:如果语言支持,则使用语言构造,或者使用强制它的模式(例如,,模板方法),或者使您的编译依赖于通过的测试,并设置测试来执行它。

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

关于c++ - 如何确保虚方法调用一直传播到基类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1273385/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com