C ++:如何遍历类类型列表以进行类型标识验证和向下转换?

Posted

技术标签:

【中文标题】C ++:如何遍历类类型列表以进行类型标识验证和向下转换?【英文标题】:C++: How to iterate over a list of class types for typeid verification and downcasting? 【发布时间】:2021-10-15 01:37:02 【问题描述】:

我想在执行时进行向下转换。 对于我阅读的内容,如果我想这样做,我需要将我的多态指针的typeid 与我的派生类的那些进行比较,然后以正确的类型进行转换。 另外,假设我有大量的派生类。 这意味着我必须写一个很长的switchif 的列表。 我想通过使用要检查的类列表来减少这项工作。

这可能看起来像:

#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 derrived 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 呢?或者换句话说,我如何遍历类类型列表以进行typeid 比较和强制转换?

更多细节:

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

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

    从基指针开始。 获取派生指针并将其提供给外部函数(此处称为function_only_for_Rectangle,因此我无法修改此函数)。 我不能做一个简单直接的dynamic_cast&lt;ClassRectangle&gt;(p),因为p(或等效的Shape1)的类型会在运行时改变。这意味着Shape1 可以“随机”拥有来自BaseShapes 的任何派生类型。所以我需要一些“自动”的东西,这就是为什么我正在考虑迭代所有派生类型并根据typeid 匹配向下转换(但我愿意接受更好的想法)。

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

【问题讨论】:

你根本不会那样做,你只是遍历基础对象并调用它的虚函数,然后让编译器和运行时多态发挥它的“魔力”。 一个函数只能有 1 个返回类型,并且必须在编译时知道。使用auto只是意味着你不需要自己指定类型是什么,编译器会为你做。 你为什么认为你需要做任何向下转换?你已经有了一个抽象接口。 @Someprogrammerdude 我编辑了我的问题,我认为这个编辑回复了你的 cmets:我不能做纯粹的多态性(我想做,但它不是来自我)。 @πάνταῥεῖ 我编辑了我的问题,并详细说明了我认为即使我有一个抽象接口也需要向下转换的原因。但我愿意接受任何想法来解决我的问题而不会沮丧。 【参考方案1】:

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

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

我想run 的命名只是为了示例。给它一个更好的名字,在基类中提供一个默认实现,在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; 
 

关于您的编辑:

    我不能做一个简单直接的 dynamic_cast(p) 因为 p 的类型(或等效的 Shape1)会在运行时改变。这意味着 Shape1 可以“随机”具有从 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 的指针并检查演员表是否成功。

【讨论】:

我编辑了我的问题。在一般情况下,我同意您的看法,这样做要好得多。但是我没有选择在这里沮丧以使来自“外部”的事物兼容。所以,从这个意义上说,你的答案并没有回答我的问题,即使它提供了更好的通用解决方案。 @R.N 我知道这是没有答案的。我打算为实际问题添加一些内容。穷人多态是enum subtype 和虚拟subtype getType() 或类似的东西 @R.N 但是,您的示例不是标题中问题的好示例(因为没有明显的需要强制转换)。请在问题中说明您可以更改哪些代码以及不能更改哪些代码 好的,我编辑了我的问题。我希望它更清楚,并且您有足够的思考解决方案。 @R.N 抱歉,但仍然不清楚为什么您认为您需要像 downcast_function 这样的东西。当您只想为矩形调用function_only_for_rectangle 时,可以使用dynamic_cast

以上是关于C ++:如何遍历类类型列表以进行类型标识验证和向下转换?的主要内容,如果未能解决你的问题,请参考以下文章

复合数据类型,英文词频统计

c ++如何按类类型对向量进行排序

如何以交替顺序对两个不同对象列表的 XML 数组项进行排序?

在 Typescript 中,如何设置对象的类型以反映类属性的列表?

C语言 - 隐式类型转换

如何对控件类型列表进行排序