C++ 我可以将基类提升为子类吗?

C++ 我可以将基类提升为子类吗?,c++,superclass,base-class,C++,Superclass,Base Class,我有一个a级,如下所示: struct MY_DATA { int m_nType; union { DWORD m_dwBData; double m_dCData; } u; }; class CClassA { public: CClassA(BYTE* lpData, UINT uSize); virtual ~CClassA(void); MY_DATA m_Data; }; CClassA

我有一个a级,如下所示:

struct MY_DATA
{
    int m_nType;

    union
    {
        DWORD m_dwBData;
        double m_dCData;
    } u;
};

class CClassA
{
public:
    CClassA(BYTE* lpData, UINT uSize);
    virtual ~CClassA(void);

    MY_DATA m_Data;
};

CClassA::CClassA(BYTE* lpData, UINT uSize)
{
    ::memcpy(&m_Data, lpData, uSize);
}

CClassA::~CClassA(void)
{
}
class CClassB : public CClassA
{
public:
    CClassB(BYTE* lpData, UINT uSize);
    virtual ~CClassB(void);

    void ProcessBData()
    {
        m_Data.u.m_dwBData ++;
    }
};

CClassB::CClassB(BYTE* lpData, UINT uSize)
: CClassA(lpData, uSize)
{
}

CClassB::~CClassB(void)
{
}

以及从a类衍生而来的B类,如下所示:

struct MY_DATA
{
    int m_nType;

    union
    {
        DWORD m_dwBData;
        double m_dCData;
    } u;
};

class CClassA
{
public:
    CClassA(BYTE* lpData, UINT uSize);
    virtual ~CClassA(void);

    MY_DATA m_Data;
};

CClassA::CClassA(BYTE* lpData, UINT uSize)
{
    ::memcpy(&m_Data, lpData, uSize);
}

CClassA::~CClassA(void)
{
}
class CClassB : public CClassA
{
public:
    CClassB(BYTE* lpData, UINT uSize);
    virtual ~CClassB(void);

    void ProcessBData()
    {
        m_Data.u.m_dwBData ++;
    }
};

CClassB::CClassB(BYTE* lpData, UINT uSize)
: CClassA(lpData, uSize)
{
}

CClassB::~CClassB(void)
{
}

然后我接收一个大小为uSize的内存块lpData。uSize与MY_数据的大小相同。但我事先不知道我是谁

我的目的是确定内存块的类型,并调用相应的处理函数来处理类型后面的数据。

因此,我在下面的代码片段中这样做:

    CClassA a(lpData, uSize);

    if (a.m_Data.m_nType == 0)
    {
        CClassB& b = (CClassB&)a;
        b.ProcessBData();
    }
我将使用内存块创建一个类A的实例,然后如果数据的类型为0,那么我们将知道数据属于类B,然后我将把原始实例提升到它的子类ClassB,这样我们就可以调用ProcessBData来处理特定于类B的数据

然而,我怀疑这是否有效,因为类B是a的子类,所以它将包含比类a更多的条目,通过将基类复制到它的子类,这会导致问题吗

另一种解决方案是在知道类型为0后,使用相同的内存块创建类B的新实例。但是,这会降低性能,因为我们复制内存块两次,一次复制到类A,一次复制到类B

那么如何解决这样的难题呢


谢谢

如果不添加/获取有关数据内容的任何类型的信息,就无法在运行时获取类型信息。如果您能够以某种方式获取类型信息,那么有一些解决方案

  • 要么在处理之前设置
    struct MY_DATA::m_nType
    ,通过查看数据获取其类型(可能数据中有某种标识符,特定类型的特定值范围,不同数据类型的不同大小)
  • 文档为您提供了一些您将收到的信息类型的信息
  • 您可以更改
    MY_DATA
    的声明并使用
  • 解决方案1: 例如,对于DWORD和double,您可以使用数据的大小

    std::cout << sizeof(unsigned int) << std::endl;
    >> 4
    std::cout << sizeof(bouble) << std::endl;
    >> 8
    
    myclass.cpp

    #include "myclass.h"
    
    #include <cstring>
    #include <iostream>
    
    CClassB::CClassB(MY_DATA* lpData){
      m_Data = new MY_DATA_B;
      memcpy(m_Data, lpData, sizeof(MY_DATA_B));
    }
    
    CClassB::~CClassB(){
      delete m_Data;
    }
    
    void CClassB::myMethodB(){
      std::cout << "MY_DATA_B data: " <<  m_Data->data << std::endl;
    }
    
    CClassC::CClassC(MY_DATA* lpData){
      m_Data = new MY_DATA_C;
      memcpy(m_Data, lpData, sizeof(MY_DATA_C));
    }
    
    CClassC::~CClassC(){
      delete m_Data;
    }
    
    void CClassC::myMethodC(){
      std::cout << "MY_DATA_C data: " << m_Data->data << std::endl;
    }
    

    如果你真的只是得到一堆内存,而没有任何关于它的内容的进一步信息,并且想要得到信息的类型=>那么你的设计就无法修复了。

    弄清楚你到底想做什么是一种挑战。。。据我所知,如果您试图从基类强制转换到派生类,这可能是格式错误的,并可能导致U.B.或不受欢迎的定义行为。。。这真的很难说,因为这取决于它将被用于的上下文,角落案例等等

    这里有一个可能的建议结构可以帮助你。。。它通过模板专门化和CRTP结构的组合使用多态继承。它可能看起来像这样:

    template<class T, int type>
    class Data {
    protected:
        Data() {};
    public:
        virtual ~Data() {}
    };
    
    template<class T>
    class Data<T, 0> {
    protected:
        DWORD data;
    };
    
    template<class T>
    class Data<T, 1> {
    protected:
        double data;
    };
    
    template<typename T, int type>
    class Base : public Data<T, type> {
    protected:
        Base() {}
    public:
        virtual ~Base() {}
        virtual void processData() {}
    };
    
    class ClassA : public Base<ClassA, 0> {
    public:
        ClassA(const BYTE* lpData, UINT size) {
            ::memcpy( &(this->data), lpData, size);
        }
    
        void processData() override {
            return;
        }
    };
    
    class ClassB : public Base<ClassB, 1> {
    public:
        ClassB(const BYTE* lpData, UINT size) {
            ::memcpy( &(this->data), lpData, size);
        }
    
        void processData() override {
            data++;
        }
    };
    
    模板
    类数据{
    受保护的:
    数据(){};
    公众:
    虚拟~Data(){}
    };
    模板
    类数据{
    受保护的:
    DWORD数据;
    };
    模板
    类数据{
    受保护的:
    双重数据;
    };
    模板
    类库:公共数据{
    受保护的:
    Base(){}
    公众:
    虚拟~Base(){}
    虚拟void processData(){}
    };
    A类:公共基地{
    公众:
    ClassA(常量字节*lpData,单位大小){
    ::memcpy(&(this->data),lpData,size);
    }
    void processData()重写{
    返回;
    }
    };
    B类:公共基地{
    公众:
    ClassB(常量字节*lpData,单位大小){
    ::memcpy(&(this->data),lpData,size);
    }
    void processData()重写{
    数据++;
    }
    };
    
    如果基类实际上不是子类,则绝对不要将其强制转换为子类。在我看来,实例化哪个类的决定应该由工厂函数根据手头的数据来处理。为什么不简单地实现一些移动语义呢?或者,如果旧对象必须保持有序,那么让另一个类不是子类,而是存储指向第一个类的指针。我也确实认为指针是正确的方法。工厂创建一个包含指针的对象怎么样?您的代码段包含UdeVior。在某些情况下,它可能与某些编译器一起工作,但在其他情况下它会失败。如果
    ClassB
    会有额外的数据成员,那肯定是非常危险的。从“写一个完美的问题”>
    开始,许多海报陷入的一个陷阱是问如何实现一些“小”目标,但永远不要说更大的目标是什么。
    那么你的目标是什么?什么是
    lpData
    uSize
    ,您如何使用它们?如何初始化m_数据?在这种情况下,为什么需要继承?如果没有这些信息,就不会出现两难的局面,因为不清楚选项是什么。实际上,我在评论中使用了指针建议。无论如何,谢谢你。
    template<class T, int type>
    class Data {
    protected:
        Data() {};
    public:
        virtual ~Data() {}
    };
    
    template<class T>
    class Data<T, 0> {
    protected:
        DWORD data;
    };
    
    template<class T>
    class Data<T, 1> {
    protected:
        double data;
    };
    
    template<typename T, int type>
    class Base : public Data<T, type> {
    protected:
        Base() {}
    public:
        virtual ~Base() {}
        virtual void processData() {}
    };
    
    class ClassA : public Base<ClassA, 0> {
    public:
        ClassA(const BYTE* lpData, UINT size) {
            ::memcpy( &(this->data), lpData, size);
        }
    
        void processData() override {
            return;
        }
    };
    
    class ClassB : public Base<ClassB, 1> {
    public:
        ClassB(const BYTE* lpData, UINT size) {
            ::memcpy( &(this->data), lpData, size);
        }
    
        void processData() override {
            data++;
        }
    };