lançar objeto de classe para objeto de estrutura C / C ++

Nov 27 2020

Tenho dois projetos, um em C e o outro em C ++, e tento converter um objeto de classe em C ++ para um objeto de estrutura em C. Por exemplo, tenho um objeto de myClass que estou tentando converter em myStru da seguinte maneira:

Em meu projeto C ++, tenho esta classe:

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

No meu projeto C, tenho esta estrutura:

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

Agora, em meu projeto C ++, crio um objeto a partir de myClass:

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

No meu projeto C, recebo classObjcomo um ponteiro vazio e tento lançá-lo da seguinte maneira:

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

Eu faço isso mais tarde no meu projeto C ++

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

O que estou fazendo aqui está certo? ou seja, lançar classObjpara struObjdessa forma?

O exemplo completo pode ser encontrado aqui (obrigado @Borgleader) http://coliru.stacked-crooked.com/a/05543b944ee23f2f

EDIT: Eu encontrei uma boa resposta para minha pergunta neste artigo (consulte Acessando classes C ++ de C): https://www.oracle.com/technical-resources/articles/it-infrastructure/mixing-c-and-cplusplus.html

Respostas

3 BartekBanachewicz Nov 27 2020 at 13:22

Não tenho 100% de certeza, porque é C ++ e você nunca pode ter, mas acho que esse é um comportamento indefinido.

Você não pode acessar os membros de uma estrutura por meio de um ponteiro para um membro de outra estrutura. Uma notável exceção a essa regra envolve o acesso à sequência inicial comum de duas estruturas que são membros de um sindicato.

Isso pode funcionar se você realmente herdar sua classe da estrutura.

Alternativamente, a outra exceção é que você pode com segurança memcpyentre essas estruturas, AFAIR.

1 Persixty Nov 27 2020 at 17:08

Esta pergunta é sobre interoperabilidade e você nunca obterá uma resposta definitiva porque ela depende de aspectos definidos pela implementação do compilador C e C ++. O structe o classsão tipos compatíveis com layout em termos de C ++. É muito claro que declarar um a classe um a structnão é um problema e porque ambos têm o mesmo acesso de membro para todos os seus membros (embora diferentes um do outro) são compatíveis (pelo menos em C ++ 14 em diante, eu acredito) .

O melhor que o padrão vai oferecer é:

Observação: as classes de layout padrão são úteis para a comunicação com o código escrito em outras linguagens de programação. Seu layout é especificado em 12.2. - nota final

A intenção é que tais classes (que são compatíveis com layout padrão e layout) sejam interoperáveis. Se você estiver usando o mesmo compilador em dois modos, seria 'decepcionante' se isso não funcionasse. Mas isso é o melhor que você obterá 'decepcionante' - verifique a documentação.

Eu me pergunto um pouco sobre o gerenciamento de recursos na estratégia geral. Você declarou um destruidor no C ++ classe tudo bem, não é virtual!), Mas você o copia para um structno lado C, se o código C tiver uma função 'semelhante ao destruidor' para destruir seus objetos, o que pode causar problemas porque clonou bit a bit o objeto C ++ (espero!).

Se C chamou free(s->data)sua cópia de um objeto construído em C ++ que o usou, newvocê está provocando um comportamento indefinido. Esse pode ser o caso, exceto que garante o uso malloc()do lado C ++ para compatibilidade.

Portanto, provavelmente está tudo bem, mas você está contando com recursos de interoperabilidade entre C e C ++ e os dois padrões levam você o mais longe possível, mas por definição você está usando recursos definidos de implementação.

Por essa nota, sabemos que o padrão está disposto a funcionar e provavelmente funcionará. Boa sorte!