Search code examples
c++superclassbase-class

Can I promote base class to child class?


I have a class A, as below:

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)
{
}

and a class B derived from class A, as below:

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)
{
}

Then I recieve a memory block lpData with size of uSize. uSize is same as the size of MY_DATA. But I don't know m_nType in advance.

My purpose is to determine the type of the memory block and invoke the corresponding processing function to process the data follows the type.

So I do that in the following code snippet:

    CClassA a(lpData, uSize);

    if (a.m_Data.m_nType == 0)
    {
        CClassB& b = (CClassB&)a;
        b.ProcessBData();
    }

I will create an instance of Class A by using a memory block, then if the type of the data is 0, then we will know the data is of class B, then I will promote the oriignal instance to its child class ClassB so that we can invoke ProcessBData to process the data specific to class B.

However, I doubt if this will work, since class B is a child class of A, so it will contain more entries than class A, by prmoting a base class to its child class, will that cause problem?

Another solution is create a new instance of Class B after knowing the type is 0, with the same memory block. However, this will decrease the performance, since we copy the memory block twice, once to class A and once to class B.

So how to solve such a delimma?

Thanks


Solution

  • You cannot get the type information at runtime, without adding/getting any type of information about the content of the data. There are some solutions if you can get type information somehow

    1. Either you set struct MY_DATA::m_nType befor processing it by getting it's type by looking at the data (maybe you have some kind of identifier inside your data, specific value ranges for a specific type, different size for different data types).
    2. Documentation gives you some information of what kind of information you will receive
    3. You can change the declaration of MY_DATA and use Runtime Type information

    Solution 1: In case of DWORD and double you could for example use the size of the data

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

    if you have acces to the original creation of data.

    Solution 2: Well, apparently look at your documentation or ask the developer who provided the data.

    Solution 3: Use Runtime Type information for your MY_DATA struct. This could look as following:

    myclass.h

    #pragma once
    
    #include <cstdint>
    
    struct MY_DATA{
      virtual ~MY_DATA() {};
    };
    
    struct MY_DATA_B : public MY_DATA{
        unsigned int data;
    };
    
    struct MY_DATA_C : public MY_DATA{
        double data;
    };
    
    class CClassB {
    public:
        CClassB(MY_DATA* lpData);
        virtual ~CClassB(void);
    
        void myMethodB();
    
    private:
      MY_DATA_B* m_Data;
    };
    
    class CClassC {
    public:
        CClassC(MY_DATA* lpData);
        virtual ~CClassC(void);
    
        void myMethodC();
    
    private:
      MY_DATA_C* m_Data;
    };
    

    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;
    }
    

    main.cpp

    #include "myclass.h"
    
    #include <iostream>
    #include <typeinfo>
    
    
    void execute(MY_DATA * ptr){
      if(typeid(*ptr) == typeid(MY_DATA_B)){
        CClassB a(ptr);
        a.myMethodB();
      }else if(typeid(*ptr) == typeid(MY_DATA_C)){
        CClassC a(ptr);
        a.myMethodC();
      }
    }
    
    int main(){
      MY_DATA_B b;
      b.data = 5;
      MY_DATA_C c;
      c.data = 3.1;
    
      MY_DATA * ptr = &b;
      MY_DATA * ptr2 = &c;
    
      execute(ptr);
      execute(ptr2);
      
      return 0;
    }
    

    This will result in the following output:

    MY_DATA_B data: 5
    MY_DATA_C data: 3.1
    

    If you really just get a bunch of memory without any further information about it's content and want to get the type of the information => Then your design is broken beyond repair.