Uma estrutura C pode se comportar como se tivesse uma função?

13

Eu uso C e struct s onde uma estrutura pode ter membros, mas não funções. Suponha, por simplicidade, que eu quero criar uma estrutura para cadeias que eu nomeie stre que seja capaz de fazer str.replace(int i, char c)onde ié o índice da cadeia e co caractere para substituir o caractere na posição i. Isso nunca seria possível, já que estruturas não podem ter funções ou ainda existe alguma maneira de implementar esse comportamento e imitar que uma estrutura poderia ter uma função (simples) que, na verdade, é apenas a estrutura que está se copiando para uma nova estrutura e atualizando sua estrutura? campos, o que poderia fazer?

Portanto, replacepoderia ser um terceiro membro da estrutura que aponta para uma nova estrutura que é atualizada quando é acessada ou semelhante. Isso poderia ser feito? Ou há algo embutido ou alguma teoria ou paradigma que impeça minha intenção?

O pano de fundo é que estou escrevendo código C e me vejo reinventando funções que eu sei que são bibliotecas embutidas em linguagens OOP e que OOP seria uma boa maneira de manipular seqüências de caracteres e comandos.

Niklas
fonte
5
Sinceramente, acho que seria melhor escrever funções gratuitas para fazer esse tipo de coisa. No entanto, se você tiver o moxie necessário, leia cs.rit.edu/~ats/books/ooc.pdf
Robert Harvey
5
Estruturas podem incluir variáveis ​​que são indicadores de funções. Não há herança incorporada, mas você pode instanciar sua estrutura com os ponteiros apontando para diferentes funções com a mesma assinatura. Você geralmente desejará tornar o primeiro parâmetro da função um ponteiro para a estrutura.
James McLeod
29
é substituir (& str, i, c) realmente muito pior do que str.replace (i, c)? Sua pergunta não é realmente sobre as funções que substituem, é sobre a tentativa de smush uma nova sintaxe em C.
Whatsisname
1
@RobertHarvey Obrigado pelo link cs.rit.edu/~ats/books/ooc.pdf . Bom livro (e o preço é justo).
John Forkosh
3
@ whatsisname: Em C, você precisa passar o ponteiro da estrutura para a função de qualquer maneira, para terminar de str.replace(&str, i, c)qualquer maneira. C ++ automatiza a passagem do thisponteiro, é claro.
Jonathan Leffler

Respostas:

21

Sua função deve ficar assim.

void
replace(struct string * s, int i, char c);

Isso aceita um ponteiro para o objeto para operar como o primeiro parâmetro. Em C ++, isso é conhecido como othis -pointer e não precisa ser declarado explicitamente. (Compare isso com o Python, onde for necessário.)

Para chamar sua função, você também passaria esse ponteiro explicitamente. Basicamente, você negocia oo.f(…) sintaxe pela f(&o, …)sintaxe. Não é grande coisa.

A história se torna mais envolvida se você deseja apoiar o polimorfismo (também conhecido como virtualfunções). Também pode ser emulado em C (eu mostrei para esta resposta ), mas não é bonito de fazer manualmente.

Como Jan Hudec comentou, você também deve criar o hábito de prefixar o nome da função com o nome do tipo (ou seja string_replace), porque C não possui espaços de nome, portanto, pode haver apenas uma única função nomeada replace.

5gon12eder
fonte
17
É claro que a função provavelmente terá de ser chamado string_replace, porque C não tem função de sobrecarga quer e que são susceptíveis de ter algum outro replacepor algum outro tipo ...
Jan Hudec
2
Não pode ser nomeado string_replace. Nomes que começam com str, memou wcsseguido de uma letra minúscula são reservados para futuras ampliações.
David Conrad
43

As estruturas podem conter ponteiros de função , mas esses são realmente necessários apenas para métodos virtuais. Métodos não virtuais em C orientado a objeto geralmente são feitos passando a estrutura como o primeiro argumento para uma função regular. Olhe para a Gobject um bom exemplo de uma estrutura OOP para C. Ele usa macros para lidar com grande parte do padrão necessário para herança e polimorfismo.

C foi criado há 44 anos. É uma linguagem muito popular para código aberto. Você não é a primeira pessoa a pensar que strings C padrão são desajeitadas para trabalhar. Faça algumas pesquisas por bibliotecas de cadeias C. Você não precisa reinventar a roda.

Karl Bielefeldt
fonte
2
Outro exemplo notável é o CPython. O código utiliza uma série de conceitos OOP ainda é 100% puro C.
Bakuriu
@Bakuriu Eu acho que você está confundindo Cython e CPython
gato
1
@cat Ele provavelmente significa que o API Python C, Cython não é 100% puro C. docs.python.org/c-api/intro.html
JAB
5
@cat Não. Veja as fontes do CPython. De fato, a maioria das coisas é feita usando o paradigma OOP e fornece uma API OOP que corresponde principalmente à API python.
Bakuriu 25/05
1
@Bakuriu Oh, você quer dizer o tempo de execução, a fonte e a API C do Python, não a linguagem Python. o seu comentário não fez isso muito claro
gato
8

Com ponteiros de função, você pode fazer:

str.replace(&str, i, c);

Geralmente, isso só é útil se a implementação puder mudar; nesse caso, você deve usar uma vtable para que a sobrecarga seja apenas um ponteiro por estrutura:

str.vtable->replace(&str, i, c);
o11c
fonte
3
Eu continuaria a chamá-lo como string_replace (& str, i, c) e depois usar a vtable dentro de string_replace em vez de informar o site de chamada sobre a vtable.
Pete Kirkham
2
@Pete Os nomes que começam com str(ou memou wcs) e uma letra minúscula são reservados pelo padrão C para extensões futuras, portanto, não o chame string_replace. str_replaceestá bem.
David Conrad
3

Sim, eles podem, mais ou menos. Você pode usar o fato de que C permite que ponteiros funcionem em blocos de memória, também conhecidos como ponteiros de função, e que você pode criar interface como polimorfismo e funções virtuais (mesmo que não seja tão bonita).

Eu escrevi um post sobre esse assunto, seguindo uma pergunta de um dos meus alunos, recentemente, referente ao código de interface em C e Go, você pode lê-lo aqui:

Postagem em blog sobre interfaces não OO

Veja se isso lhe dá alguma idéia.

Você também pode simplesmente colocar uma função livre em seu código e usar um ponteiro "this", o que significa que você passa um ponteiro para uma estrutura existente para trabalhar, conforme descrito em outras respostas.

Richard Tyregrim
fonte