在C++中将overriden类方法作为链调用

Calling overriden class methods as a chain in C++

本文关键字:调用 类方法 C++ 中将 overriden      更新时间:2023-10-16

不止一次,我觉得有必要定义以类似于构造函数或析构函数的方式调用的类方法。

一个具体的例子是:;在一个程序中,我有一个由不同类型的节点组成的非常复杂的网络,这些节点以非常不规则的方式相互依赖(这个网络根本不像树)。当一个节点需要被破坏时,它会在网络中启动一系列复杂的破坏。就像一张被撕裂的蜘蛛网,但更复杂。

在执行这个链的过程中,控制权又回到了启动器(或链中的一个中间元素)的方法上,因此实际的销毁必须在链稳定下来时进行,这就是为什么我不能为此目的使用析构函数。然而,沿着我的节点的类层次结构,我需要一个"类似析构函数"的方法,即调用我的非破坏性预析构函数的梯形方法(原因完全相同,为什么实际的析构函数也以这种方式调用,即类层次结构中的每一步都需要以不同的方式对链做出贡献)。

我最终用手给梯子编码。也就是说,类nodeBase有一个名为"preDestroyNodeBase"的方法,它完成自己的工作,并调用虚拟方法"preDestroyNode"等等,直到叶子(我知道,这样它看起来像一个构造函数,但相对而言,它更优雅,因为你可以调用最基类的"preDestination")。

你可以想象这种方法是多么容易出错,更不用说丑陋了。有没有一种更干净的方法来模拟构造函数或析构函数调用方法?某种模板魔术,甚至宏魔术!因为手工编码太容易出错,即使对于单个程序员来说也是如此,所以我无法想象将这种行为暴露给库的客户端。

也许我错过了一个基本的编程概念,它抛弃了对此类函数的需求。如果是这样的话,如果你能指出如何处理节点网络的例子,我会很高兴。

非常感谢!

当您声明一个虚拟函数时,它将调用该函数的最派生处理程序,然后从那里开始,每个处理程序都调用NextMostDerivedClass::preDestroy,调用将转到该函数的下一个最派生的处理程序,您可以再次调用NextMostDerivedClass::preDestroy,依此类推。这与虚拟析构函数所采用的路径相同,除了你不必用析构函数手动调用任何东西之外,它是自动的。如果将以下代码示例中的cout语句放入析构函数中,则可以看到与以下示例提供的输出相同的输出。

#include <iostream.h>
class Foo
{
    public:
    virtual void PreDestroy()
    {
        cout << "Foo preDestroy";
    }
}
class Bar : public Foo
{
    public:
    void PreDestroy()
    {
        cout << "Bar preDestroynn";
        Foo::PreDestroy();
    }
}
class MostDerived : public Bar
{
    public:
    void PreDestroy()
    {
        cout << "MostDerived preDestroynn";
        Bar::PreDestroy();
    }
}
int main() 
{
    MostDerived testObj;
    testObj.PreDestroy();
}

输出应为:

MostDerived预销毁

条形码预销毁

Foo预销毁

您可以使用访问者模式浏览节点图(我假设您谈论的是一个图),并让节点将自己放入访问者对象持有的一种"待删除"列表(如果需要)中。在第二次迭代中,您可以遍历列表元素,并对它们调用一种"destroy"方法,该方法反过来进行最终清理。这种方法需要让所有节点都支持访问者模式并包含"destroy"方法。

我会使用订阅机制,如果你想让a持有指向另一个对象的指针,你还必须订阅它们的销毁事件;收到此类事件后,取消他们对您自己事件的订阅,并清理您自己的结构(这可能会导致进一步的破坏)。

即(为简洁起见,C++1x语法)

struct node {
    ~node() { for(auto i : subscribers) i->notify(this); }
    void subscribe(node *n) { subscribers.push_back(n); }
    void notify(node *n) { subscribers.remove(n); /* Handle other node being removed */ }
private:
    std::list<node *> subscribers;
}

要访问节点的数据成员,需要通过扩展节点类本身或使用从实际包含数据的类继承的模板化节点类,使它们成为节点类的子对象。