C++:如何迭代 class 类型的列表以进行 typeid 验证和向下转换?

C++: How to iterate over a list of class types for typeid verification and downcasting?

我想在执行时进行向下转换。

根据我的阅读,如果我想这样做,我需要将多态指针的 typeid 与派生的 classes 进行比较,然后以正确的方式进行转换类型。

另外,假设我有大量派生的 classes。 这意味着我必须写一个长 switchif.

的列表

我想通过使用 classes 的列表来检查来减少这项工作。

这可能看起来像:

#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <map>

using namespace std;

class BaseShapes
{
        virtual int run() = 0;
};

class ClassRectangle : public BaseShapes
{
        int run()
        {
            std::cout << "I am a Rectangle. " << std::endl;
            return 0;
        }

        float get_length () {return 12.4;};
        float get_width() {return 6.2;};
};

class ClassCircle : public BaseShapes
{
        int run()
        {
            std::cout << "I am a Cricle. " << std::endl;
            return 0;
        }

        float get_diameter() {return 5.3;};
};

float function_only_for_Rectangle(ClassRectangle *rectangle)
{
   // a function coming from a library that I cannot touch and that requires a derived type.
   // But for the example I do something dummy!
   return rectangle->get_length()
};

auto downcast_function (auto *p)
{
    enum ListOfTypes {
        ClassCircle,
        ClassRectangle,
        // and a lot more differents classes
    };

    for ( int fooInt = ClassCircle; fooInt < ClassRectangle; fooInt++ )
    {
        ListOfTypes fooItem = static_cast<ListOfTypes>(fooInt);
        if (typeid(p) == typeid(fooItem))
        {
            auto pCasted =dynamic_cast<fooItem>(p);
            return pCasted;
        }
    }
    
    std::cout<< "downcast_function warning: no typeid is matching !" << std::endl;
    return p;
};

int main(void) 
{ 
    // Beginning of main.
    cout << "(Start)" << endl;
    
        std::unique_ptr<BaseShapes> Shape1(new ClassRectangle());
        auto p=Shape1.get();
        //function_only_for_Rectangle(p); // not working since p is of type BaseShapes*
        auto pbis=downcast_function(p); // should be of type ClassRectangle*
        function_only_for_Rectangle(pbis);
    
    // End of the main.
    cout << "(End) " << endl;   
    return 0; 
} 
// EoF

那我怎么写 downcast_function 呢?或者换句话说,我如何遍历 class 类型的列表以进行 typeid 比较和转换?

更多详情:

我同意在这个虚拟示例中,我可以简单地为每个派生的 class 覆盖一个函数,这是处理多态性的更好方法。但我需要沮丧,这是一个来自更复杂问题的约束,在这些问题中,我不允许更改它们。所以,这里的问题不是为什么沮丧,而是如何沮丧。

要提供有关我的约束的更多详细信息:

  1. 从基指针开始。

  2. 得到一个派生指针,交给一个外部函数(这里叫function_only_for_Rectangle,所以我不能修改这个函数)

  3. 我不能做一个简单直接的dynamic_cast<ClassRectangle>(p),因为p(或等效的Shape1)的类型会在运行时改变。这意味着 Shape1 可以“随机地”拥有来自 BaseShapes 的任何派生类型。所以我需要一些“自动”的东西,这就是为什么我考虑迭代所有派生类型并根据 typeid 匹配进行向下转换(但我愿意接受更好的想法)。

如果需要,所有 classes 都可以修改。

你说“多态”,但你想做的恰恰相反

您可以实际使用它,而不是试图反对多态性。如果所有 subclasses 都有自己的虚函数实现,那么调用者不需要关心对象的实际动态类型是什么。简而言之就是运行时多态性。

我想 run 的命名只是为了举例。给它一个更好的名字,在基础 class 中提供默认实现,在 ClassRectangle 中实现特定行为并让调用者调用它。不用投。

class BaseShapes
{
        virtual int do_something_rectangly() { return 0;}
        ~virtual BaseShapes() = default;
};

class ClassRectangle : public BaseShapes
{
        int do_something_rectangly() override
        {
            std::cout << "I am a Rectangle. " << std::endl;
            return 0;
        }
};

class ClassCircle : public BaseShapes
{
    // does not override do_something_rectangly()
};

int function_for_any_base_shape(BaseShapes& s)
{
   return s.do_something_rectangly();
};

int main(void) 
{ 
    // Beginning of main.
    cout << "(Start)" << endl;
    
    std::unique_ptr<BaseShapes> Rec1(new ClassRectangle());
    function_for_any_base_shape(*pbis);
    
    cout << "(End) " << endl;   
    return 0; 
} 

关于您的编辑:

  1. I cannot do a simple and direct dynamic_cast(p) because the type of p (or equivalently Shape1) will change at running time. This means that Shape1 can have "randomly" any derived type from BaseShapes. [...]

要么我完全误解了你写的内容,要么你误解了 dynamic_cast 的工作原理。 dynamic_cast 确实已经检查了对象的动态类型是什么:

BaseShapes* b1 = new ClassCircle;
if(ClassRectangle* d = dynamic_cast<ClassRectangle*>(b1))
{
    // cast is sucessfull
    function_only_for_Rectangle(d);
} else {
    // dynamic type of b1 is not ClassRectangle
}

要调用 function_only_for_Rectangle,您不需要能够转换为 ClassBase 的所有子类型。您只需要 dynamic_cast 指向 ClassRectangle 的指针并检查转换是否成功。