简体   繁体   中英

cast class object to struct object C/C++

I have two projects one in C and the other in C++ and I try to cast a class object in C++ to a structure object in C. For example, I have an object from myClass which I'm trying to cast to myStru as follows:

In my C++ project I have this class:

class myClass{
    myClass();
    ~myClass();
    char    *data;
    int     var;
}

In my C project I have this structure:

struct myStru {
    char  *data;
    int    var;
};
typedef struct myStru myStru;

Now in my C++ project I create an object from myClass :

myClass *classObj = new myClass();
classObj->data = new char[10];
classObj->var  = 99;

In my C project I receive classObj as a void pointer and I try to cast it as follows:

myStru *struObj = (myStru*)malloc(sizeof(struct myStru));
struObj = (myStru*) classObj;
printf(" struObj->var %d \n", struObj->var); // this print 99

I do this later in my C++ project

   delete []classObj->data; // I know smart pointers can be used here but this is not my point in this question now
    delete  classObj;

Is what I'm doing here right? ie, casting classObj to struObj in that way?

The full example can be found here (thanks @Borgleader) http://coliru.stacked-crooked.com/a/05543b944ee23f2f

EDIT: I found a good answer to my question in this article (see Accessing C++ Classes from C): https://www.oracle.com/technical-resources/articles/it-infrastructure/mixing-c-and-cplusplus.html

I am not 100% sure, because it's C++ and you can never be, but I think this is undefined behaviour.

You cannot access the members of a struct via a pointer to a member to another struct. A notable exception of that rule involves accessing the common initial sequence of two structs that are members of a union.

This could work if you actually inherited your class from the struct instead.

Alternatively, the other exception is that you can safely memcpy between such structs, AFAIR.

This question is about inter-operability and you'll never get a definitive answer because it relies on implementation defined aspects of the C and C++ compiler. The struct and the class are layout-compatible types in C++ terms. It's very clear that declaring one a class and one a struct isn't an issue and because they both have the same member-access for all their members (though different from each other) are compatible (at least in C++14 onwards I believe).

The best the standard is going to offer is:

Note: Standard-layout classes are useful for communicating with code written in other programming languages. Their layout is specified in 12.2. — end note

The intention is that such classes (which are both standard-layout and layout-compatible) be inter-operable. If you're using the same compiler in two modes then it would 'disappointing' if this didn't work. But that's the best you'll get 'disappointing' - check the documentation.

I do wonder a bit about the resource managementin the overall strategy. You've declared a destructor in the C++ class and that's fine it's not virtual ,), but you copy it into a struct on the C side, if the C code has a 'destructor like' function to destroy its objects that may lead to trouble because you've bitwise cloned the C++ object (hopefully.).

If C called free(s->data) on its copy of an object constructed in C++ that had used new you're provoking Undefined Behaviour. That might be the except case that warrants using malloc() on the C++ side for compatibility.

SO it's probably OK, but you're relying on inter-operability capabilities between C and C++ and the two standards take you as far as it can but by definition you're using implementation defined features.

By that note we know the standard is willing it to work and it probably will. Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM