Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 266
alancc Avatar asked Apr 09 '26 21:04

alancc


1 Answers

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.

like image 173
A.K. Avatar answered Apr 11 '26 10:04

A.K.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!