【问题标题】:Downcasting best-practice (C++)向下转型最佳实践 (C++)
【发布时间】:2017-02-04 14:06:58
【问题描述】:

静态代码分析工具往往会喋喋不休地谈论“将基类向下转换为派生类”,我还发现了一些编码标准指南,其中提到不要这样做,所以我想知道最佳实践是什么方式。

这是我的用例:

我有一个 Base(接口)、DerivedA、DerivedB 类,然后是一个包含 Base 指针的数组。

然后我遍历数组并根据一个标志,确定对象是 DerivedA 还是 DerivedB,将其向下投射并从外部对对象执行一些随机操作。

基本上是这样的:

// arr is of type Base**
for (int i = 0; i < size; ++i)
{
    // doMagic has an overload for both types
    if (arr[i]->isDerivedA())
    {
        doMagic(reinterpret_cast<DerivedA*>(arr[i]));
    }     
    else if (arr[i]->isDerivedB())
    {
        doMagic(reinterpret_cast<DerivedB*>(arr[i]));
    }
}

关于重新解释,由于嵌入式平台限制(对于 C++11 也是如此),我不能使用 dynamic_cast,但是作为接口的基类保证对象是 DerivedA 或 DerivedB。

我可以让 DerivedA 和 DerivedB 只实现纯虚拟调用,因此我不必担心向下转换任何东西,但是 DerivedA 和 DerivedB 类非常专业,doMagic 对实例做了完全不同的事情......

所以我想知道你们是如何处理这个问题的——拥有一个由非常不同的对象组成的数组,但从一个基类继承,遍历它们并从外部做一些专门的事情。

【问题讨论】:

  • 人们不得不想知道为什么DerivedADerivedB 是从Base 派生的。 Base的目的是什么?
  • 它们确实包含一些常用方法,所以我不想重新实现这些方法以及一些常用数据成员。假设它是 50/50 :)。示例将具有类似的类:Message、JsonMessage、XmlMessage - 和方法 parseMessage(JsonMessage*)、parseMessage(XmlMessage*)
  • 也许更简洁的架构是将常用方法和数据包装到第三类中,并使用与第三类的 HAS-A 关系。继承实现通常不是好的 OOP 设计。

标签: c++ polymorphism


【解决方案1】:

您可能应该尝试使用访问者模式。 这是一个简单的例子:

#include <cstdio>

class A;
class B;
class Visitor {
public:
    void visit(A &a) {
        printf("Visited A\n");
    }

    void visit(B &) {
        printf("Visited B\n");
    }
};


class A {
public:
    virtual ~A() { }

    virtual void applyVisitor(Visitor &v) {
        v.visit(*this);
    }
};

class B : public A {
public:
    ~B() override { }

    void applyVisitor(Visitor &v) override {
        v.visit(*this);
    }
};


int main() {
    A a;
    B b;

    Visitor v;

    a.applyVisitor(v);
    b.applyVisitor(v);


    return 0;
}

【讨论】:

  • 谢谢,这几乎消除了沮丧并且看起来更干净 - 只需要更多代码。
【解决方案2】:

如果你知道基类的指针指向派生类的对象,你可以使用static_cast。与 reinterpret_cast 或 C-Cast 不同,编译器将插入适当的代码来调整偏移量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-27
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多