通过 C++ 中的 std 迭代器将基类转换为派生

Posted

技术标签:

【中文标题】通过 C++ 中的 std 迭代器将基类转换为派生【英文标题】:Casting base class to derived through std iterator in C++ 【发布时间】:2014-03-11 13:49:50 【问题描述】:

在我的程序中,我有从 GeneralHeader 和 NetworkPacket 派生的基本 GeneralHeader、MacHeader,其成员 Headers 是 GeneralHeader 的标准列表:

//Packet.h

enum HeaderType_t General_Header_type, MAC_Header_type;

class GeneralHeader 
public:
    bool Valid;
    HeaderType_t HeaderType;
    void PrintMe();
;

struct MACHeader: public GeneralHeader 
    long unsigned DestAddr:48;
    long unsigned SourceAddr:48;
    void PrintMe();
;

struct Packet_t 
    list<GeneralHeader> Headers;//TODO GeneralHeader
    list<GeneralHeader>::iterator it_Header; //TODO GeneralHeader
    void PrintMe();
;

在实现 Packet_t 的 PrintMe() 时,应该根据 HeaderType 打印所有标头:如果有 GeneralHeader - 它将使用 GeneralHeader.PrintMe() 并且如果它是列表中的 MACHeader - 它将打印 MACHeader。打印我()) 我正在努力将 it_Header 迭代器从基本 GeneralHeader 转换为 Packet_t 方法 PrintMe() 中的派生 MACHeader:

//Packet.cpp

void GeneralHeader::PrintMe() 
    std::cout << "Valid " << GeneralHeader::Valid << endl;
    std::cout << "Header Type " << GeneralHeader::HeaderType << endl;
;

void HW_MACHeader::PrintMe() 

    std::cout << "------------------------   " << endl;
    std::cout << "----   MAC HEADER    ---   " << endl;
    std::cout << "------------------------   " << endl;

    GeneralHeader::PrintMe();

;

void NetworkPacket_t::PrintMe() 
    std::cout << "Valid Packet " << NetworkPacket_t::ValidPacket << endl;

    for (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) 
        switch (it_Header->HeaderType) 
        case MAC_Header_type:           
            static_cast<HW_MACHeader*>(it_Header)->PrintMe();
            break;
        default:
            std::cout << "default" << endl;
        ;
        it_Header++;
    ;
;

错误:从类型“std::_List_iterator”到类型“MACHeader*”的静态转换无效

感谢您的帮助。

【问题讨论】:

您没有告诉我们Headers 是什么NetworkPacket_t,但假设它是list&lt;GeneralHeader&gt;,为什么不转换迭代值,即static_cast&lt;HM_MacHeader&gt;(*it).PrintMe()?跨度> Benjamin,我现在尝试了“static_cast(*it_Header).PrintMe()”并得到“错误:没有匹配函数调用 'HW_MACHeader::HW_MACHeader(GeneralHeader&)'” :( 【参考方案1】:

所需的/正常的多态方式是: 将 PrintMe() 重新定义为一个虚函数,这样就不需要强制转换了:

class GeneralHeader 
public:
    bool Valid;
    HeaderType_t HeaderType;
    virtual void PrintMe();
;

class MACHeader: public GeneralHeader 
    long unsigned DestAddr:48;
    long unsigned SourceAddr:48;
  public:    
     void PrintMe();
;

也使用指向 GeneralHeader 的指针向量:

list<GeneralHeader*>::iterator it_Header;

那么你可以:

(*it_Header)->printMe();

for 循环会更简单:

  for (it_Header = Headers.begin(); it_Header != Headers.end();++it_Header)
       (*it_Header)->PrintMe();

我不知道你为什么需要 it_Header 成为班级的成员?它不能只是循环的本地吗?

【讨论】:

您好 user2672165,我已经采纳了您的建议,但现在我在定义 for-loop 时遇到了困难:如何定义 for-loop 的语句 - (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) - 当迭代器按照您的建议定义时?谢谢 @Halona:添加了循环。希望对您有所帮助。【参考方案2】:

您需要取消引用it_Header 以访问“基础”对象以解决编译器错误:

static_cast<HW_MACHeader*>(*it_Header)->PrintMe();

但是,这并不能解决您的问题:您有一个 GeneralHeader 列表;因此因为要向下转换为HW_MACHeader 的实例,所以需要使用dynamic_cast;这必须在引用或指针上完成:

dynamic_cast<HW_MACHeader&>(*it_Header).PrintMe();

上面的行采用it_Header“引用”的对象,并告诉编译器将其动态转换为HW_MACHeader类型的引用。

请注意,如果dynamic_cast 无法向下转换为您想要的类型,它将返回一个空指针。

但是,这不是执行此操作的正确方法。你应该听从 user2672165 的建议,使用虚函数。

【讨论】:

Piwi,我收到错误:从类型“GeneralHeader”到类型“HW_MACHeader*”的静态转换无效

以上是关于通过 C++ 中的 std 迭代器将基类转换为派生的主要内容,如果未能解决你的问题,请参考以下文章

将基类转换为派生类[重复]

无法将基类(数据协定)转换为派生类

我们可以将基类的私有成员继承到派生类的公共成员中吗?

使用shared_ptr将基类引用值复制到映射

将基类指针强制转换为子类指针后的疑惑

什么时候在 C++ 中向上转型是非法的?