访问存储在向量 <base*> 中的已知派生类对象时,使用dynamic_cast或static_cast有什么问题?

tra*_*mot 3 c++ inheritance dynamic-cast vector static-cast

这是我的问题的后续内容: Updating data Members of different obliged Class of the same base class inside a vector

我正在 C++ 中构建一个 3D 网格模型,它具有不同的单元类型,所有单元类型都存储在Grid类中的向量中。我定义了一个GridCell基类,并且还有几个派生类GridCell1GridCell2GridCell3等。

我将GridCell对象传递到模型进程中。传递的GridCell对象类型(其派生类)将与接收模型进程一起使用。换句话说,模型进程模型进程被设计(可能是不正确的),具有不同的函数,期望对适当的派生对象的数据成员进行操作。当然,他们看不到,因为对象是从 中拉出的,std::vector<gridCell*> gridCellVector所以它只将该对象视为指向基类的指针。此时,我有两个选择:1)重写我的模型流程,2)使用static_cast或dynamic_cast向下转换传递的对象。

问题:在这种情况下,当我的模型进程(仅在正确类型的GridCell对象上运行)知道它们正在接收什么派生类时,我应该使用 static_cast 还是dynamic_cast?人们似乎真的不喜欢使用这些工具。为什么我应该远离使用这些?

Gal*_*lik 5

有时强制转换是不可避免的,因为多态性并不能解决所有问题。然而,多态性实际上是为了消除了解类型的需要而设计的。如果您需要知道类型,那么您必须询问多态性是否是适合该工作的工具,或者您是否未能正确实现多态性。

理想的情况是每个对象都知道自己的行为,以便其他人if/else在处理通用类型时不需要做出决定。

为此,您通常会将处理代码放在类型本身内部,而不是使用需要if/else为收到的每个对象做出决策的外部处理例程。

因此,虽然铸造本质上并不是坏事,因为有时这是必要的,但如果您需要使用它,它也可能是设计不良的症状。

问题:在这种情况下,当我的模型进程(仅在正确类型的GridCell对象上运行)知道它们正在接收什么派生类时,我应该使用 static_cast 还是dynamic_cast?人们似乎真的不喜欢使用这些工具。为什么我应该远离使用这些?

如果您确实知道类型,则使用static_cast(它更快),否则使用dynamic_cast.

铸造的替代方案:

您可以使用的一种“技巧”(有效的转换)是使用多态性来为您选择正确的类型。

您可以做的就是向基类添加一个虚函数GridCell,该函数获取单独处理子类型的类的对象,并让重写的子类型自行调用相关的处理函数。这样,类型本质上就知道需要如何处理它。

一个例子

class Processor
{
public:

    void process_1(class GridCell1* cell)
    {
        std::cout << "processing type 1\n";
    }

    void process_2(class GridCell2* cell)
    {
        std::cout << "processing type 2\n";
    }
};

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

    virtual void process(Processor& proc) = 0;
};

class GridCell1
: public GridCell
{
public:
    void process(Processor& proc) override
    {
        proc.process_1(this);
    }
};

class GridCell2
: public GridCell
{
public:
    void process(Processor& proc) override
    {
        proc.process_2(this);
    }
};

class Grid
{
    std::vector<GridCell*> gridCellVector;

public:
    Grid()
    {
        gridCellVector.push_back(new GridCell1);
        gridCellVector.push_back(new GridCell1);
        gridCellVector.push_back(new GridCell2);
        gridCellVector.push_back(new GridCell1);
        gridCellVector.push_back(new GridCell2);
        gridCellVector.push_back(new GridCell1);
    }

    ~Grid() { for(auto cell: gridCellVector) delete cell; }

    void process()
    {
        Processor proc;
        for(auto cell: gridCellVector)
            cell->process(proc);
    }
};

int main ()
{
    Grid grid;

    grid.process();
}
Run Code Online (Sandbox Code Playgroud)

输出:

processing type 1
processing type 1
processing type 2
processing type 1
processing type 2
processing type 1
Run Code Online (Sandbox Code Playgroud)