Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
185 views
in Technique[技术] by (71.8m points)

c++11 access members of union content via pointer

working on implementing an Serial receive library for a specific hardware sending information to a ESP8266 device, I came across the following issue

for some background:

  • I use sloeber the eclipse IDE for arduino programming, with Arduino IDE the same issue exists
  • __cplusplus gives me 201103, so I assume I am on c++11

explanation of the setup:

  • I have derived classes which represents interpreted packages received from serial
  • these classes are all derived form on base class which implements some common methods, here methodA (in reality: length of data, and getter for the data)
  • to forward these packets around I have created a class which has a member of a struct (sData) which has a tagged union inside. for simplicity I only use sData here not the class containing it.
  • the union uUnion is the one holding the packets content in form of derived packages, only one at a time, but able to contain every derived class available.
  • i do not use any dynamic object creation (no new), to prevent memory leaks

maybe there are better solution to this problem. Ideas are appreciated. But I would like to focus on why my implementation is not working

problem

the usage of the members-functions of the derived classes out of the union. I can call them directly without problem. But I am not able to create a pointer out of the union to the derived class instance and call that member.

//this is the base class
class cBaseA{
public:
    virtual void methodA(void){
            Serial.print(" A ");
            Serial.println(i);
        }
    int i; //some attribute to work with
private:
};
//first derived class
class cDerivedA: public cBaseA{
public:
     void methodA(void) {
        Serial.print(" DerivedA ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println(ii);
    }
     int ii; //additional attribute
private:
};
//second derived class
class cDerivedB: public cBaseA{
public:

     void methodA(void) {
        Serial.print(" DerivedB ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println(ii);
    }
    int ii;
private:
};
//third derived class
class cDerivedC: public cBaseA{
public:
     void methodA(void) {
            Serial.print(" DerivedC");
            Serial.print(i);
            Serial.print(" ");
            Serial.println(ii);
        }
     int ii;
private:
};
//this is the structure to pass different derived instances around
struct sData{
    enum eDataType{
        eunkown,
        eDerivedA,
        eDerivedB,
        eDerivedC
    } DataType;
    union uUnion{
        cDerivedA DerivedA;
        cDerivedB DerivedB;
        cDerivedC DerivedC;
        ~uUnion(){};
        uUnion(){};
    } ;
    uUnion DataUnion;
    sData(void){DataType=eDataType::eunkown;};
    sData(const sData &Data){
        this->DataType=Data.DataType;
        switch(this->DataType){
            case eDataType::eDerivedA:
                this->DataUnion.DerivedA=Data.DataUnion.DerivedA;break;
            case eDataType::eDerivedB:
                this->DataUnion.DerivedB=Data.DataUnion.DerivedB;break;
            case eDataType::eDerivedC:
                this->DataUnion.DerivedC=Data.DataUnion.DerivedC;break;
            case eDataType::eunkown:
                break;
        }
    }
    ~sData(){};
};


void DataFunction(struct sData *Data){
    Serial.println("A1:");
    Data->DataUnion.DerivedB.methodA();   //works fine

    cDerivedB *DerivedB;
    DerivedB=&(Data->DataUnion.DerivedB); //this works
    DerivedB->methodA();                  //compiles, but execution exception, code 28

}

void setup(){
    Serial.begin(9600);
    delay(2000);
sData Data;
    cDerivedB DerivedB1;
    DerivedB1.i=1;
    DerivedB1.ii=2;
    Data.DataType=sData::eDataType::eDerivedB;
    Data.DataUnion.DerivedB=DerivedB1;
    DataFunction(&Data);

}

what I tried so far:

  • the absence of the virtual destructor of cBaseA has no influence (I tried already with it)

  • to make the union anonymous did not changed anything

  • to make a reference to the unions content results in the same error:

    cDerivedB &DerivedB; DerivedB=&(Data->DataUnion.DerivedB); DerivedB.methodA();

  • I am able to make copy to out of the union to the base class, but this causes slicing, and the call ends in the base class, not as I need in the derived class

the question is: why does this exception happen, if the direct call is possible?

What is the right way to get a handle (pointer, reference) of the unions content and call the member? I know that there are discussions out there, that unions should only contain simple data types. Is this just a flaw of the compiler (c+11) letting me write this? But still, direct access is possible. Why not via pointer?

many thanks in advance if somebody is able to put that cloud away I can not see through.

question from:https://stackoverflow.com/questions/65644074/c11-access-members-of-union-content-via-pointer

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...