确保指向超类的指针指向c ++

时间:2018-06-21 18:37:10

标签: c++ casting polymorphism subclass

我有两个容器(分别称为A型和B型),这两个容器均源自父类型(称为AB)。父类具有Widget对象的链接列表。在我的Widget类中,我有一个指向其所在容器的指针。显然,这被声明为指向AB的指针。同样在小部件类中,我有一个方法仅在小部件的容器为A时才适用,并且它使用指向AB的指针。但是,当然,我需要将其转换为A *。

我已经考虑过在AB中将该方法设为虚拟方法,并引发错误;然后在A中覆盖它,但这令我感到困扰,因为该方法仅适用于A,而在通用AB情况下没有意义。

我已经考虑过使用dynamic_cast将父指针转换为A *。但是我也读到这暗示了糟糕的课堂设计。首选的处理方式是什么?

class Widget;

class AB
{
    private:
        Widget* firstWidget;   // first widget in a linked list, don't judge.
};

class A : public AB
{
    public:
        void methodSpecificToA() {}
};

class B : public AB {}; 

class Widget
{
    private:
        AB* container;
    public:
        void AWidgetMethod()
        {
            A* ac = static_cast<A*>(container);
            ac->methodSpecificToA();
        }

};

1 个答案:

答案 0 :(得分:1)

提到的注释中不存在基类的愿望提供了某些派生类可能需要的所有虚拟方法。这种愿望是一件好事。让我们看看我是否可以提出一些替代方案。 (我没有断言这是详尽无遗的。)请承认这些是通用的,因为问题涉及的上下文很少。所以我有点猜测。我不知道哪种方法最适合给定的情况。

在寻找替代方案之前,设计有什么问题?主要问题是Widget类对AB层次结构有所了解,然后根据此知识进行决策。您的班级彼此之间了解的越少,他们之间的隔离就越多。对于人们来说,隔离是不好的,但是对于类来说,这意味着更少的相互依赖性和更少的错误,而当其中一个类发生更改时,引入的错误也更少。理想情况下,Widget类知道通用的AB接口,并且层次结构中没有其他内容。也许从Widget派生的类对从AB派生的类有所了解。或者可能不是。可以采用不同的方法。

说发生了什么,而不是说要怎么做。出现这种情况的原因之一是,小部件通过告诉容器做某事来响应某种刺激。有时,应该看一看容器可能需要做的所有事情,并将其与容器可能需要响应的所有事情进行比较。如果每个刺激一个,而不是每个动作一个,那么您可能最终得到的虚拟功能列表会更短。另外,刺激功能应该适用于基类,而动作功能则可能不适用。 (例如,刺激的功能可能是WasPressed(Widget & widget)。)如果采用这种方法,则小部件通过告诉容器发生了刺激来响应某种刺激,让容器决定需要做什么。 。在某些情况下,这本身会减少一个班级对另一班级的了解。在其他情况下,它似乎更人为设计(在这种情况下,不一定是个好主意)。

专业类应该得到专业数据。并非总是如此。仍然有一些值得额外记账的地方,以使代码在维护时保持健壮(也就是其他人在“改进”您的代码)。我正在考虑以下情况:调用methodSpecificToA的小部件知道其容器是A,因为它是某种类型的小部件。例如,滚动条会知道其父级是可滚动区域,因为这是唯一需要滚动条的容器。在这种情况下,值得让专用窗口小部件维护自己的指向其容器的指针,并将其存储为指向A的指针。 (这是对您已经拥有的指向AB的指针的补充。)不需要强制转换,甚至可以将这种特殊功能与“我的容器”概念分开。 (也许A应该有两个基类:AB和一个定义methodSpecificToA的基类。如果这样做,专用的小部件将存储一个指向这个新基类的指针。)

使用回调。这种经典方法可以解决一个类不需要了解另一类的问题。即使该窗口小部件不是专用的,它也可以工作,但是如果不需要很多回调,则它可以最好地工作。 (如果需要许多回调,则使用上面的“专用数据”可能会更好。)使用回调时,将告知窗口小部件在发生某种刺激时调用某个function object,这就是它的作用。不知道会发生什么,也不需要指向其容器的指针。容器和窗口小部件如何交互的知识从窗口小部件转移到将窗口小部件放置在容器中的代码。 (这是设置回调的代码。)


关于这些建议,您可能会注意到的一件事是,它们都没有告诉您如何从指向methodSpecificToA的指针调用AB。这就是为什么我建议更深入地研究这类问题。一旦看到警告标记表明您可能存在设计缺陷,通常最好检查一下设计。整个设计,而不仅仅是旗标出现的一小部分。