Leia o SICP e aprenda Scheme, além da idéia prática de tipos de dados abstratos . Então codificar em C é fácil (já que com SICP, um pouco de C e um pouco de PHP, Ruby, etc ... seu pensamento seria bastante amplo e você entenderia que a programação orientada a objetos pode não ser o melhor estilo em todos os casos, mas apenas para algum tipo de programa). Tenha cuidado com a alocação de memória dinâmica C , que provavelmente é a parte mais difícil. O padrão da linguagem de programação C99 ou C11 e sua biblioteca padrão C são na verdade bastante pobres (ele não conhece TCP ou diretórios!), E muitas vezes você precisará de algumas bibliotecas ou interfaces externas (por exemplo,POSIX , libcurl para a biblioteca do cliente HTTP, libonion para a biblioteca do servidor HTTP, GMPlib para bignums, alguma biblioteca como libunistring para UTF-8, etc ...).
Seus "objetos" geralmente estão em C - alguns relacionados struct
- e você define o conjunto de funções operando neles. Para funções curtas ou muito simples, considere defini-las, com o relevante struct
, como static inline
em algum arquivo de cabeçalho, foo.h
para estar #include
-d em outro lugar.
Observe que a programação orientada a objetos não é o único paradigma de programação . Em algumas ocasiões, outros paradigmas valem a pena ( programação funcional à Ocaml ou Haskell ou mesmo Scheme ou Commmon Lisp, programação lógica à Prolog, etc etc ... Leia também o blog de J.Pitrat sobre inteligência artificial declarativa). Veja o livro de Scott: Pragmática da Linguagem de Programação
Na verdade, um programador em C ou Ocaml geralmente não deseja codificar em um estilo de programação orientado a objetos. Não há razão para se forçar a pensar em objetos quando isso não é útil.
Você definirá algumas struct
e as funções que operam nelas (geralmente através de ponteiros). Você pode precisar de algumas uniões marcadas (geralmente uma struct
com um membro de tag, muitas vezes algumas enum
e algumas union
internas), e pode ser útil ter um membro de matriz flexível no final de alguns dos seus struct
-s.
Olhe dentro do código fonte de alguns softwares livres existentes em C (consulte o github & sourceforge
para encontrar alguns). Provavelmente, a instalação e o uso de uma distribuição Linux seria útil: ela é feita quase apenas de software livre, possui ótimos compiladores C de software livre ( GCC , Clang / LLVM ) e ferramentas de desenvolvimento. Consulte também Programação avançada do Linux se você deseja desenvolver para Linux.
Não se esqueça de compilar com todos os avisos e informações de depuração, por exemplo - gcc -Wall -Wextra -g
notavelmente durante as fases de desenvolvimento e depuração - e aprender a usar algumas ferramentas, por exemplo, valgrind para detectar vazamentos de memória , o gdb
depurador, etc. Lembre-se de entender bem o que é indefinido comportamento e evite-o fortemente (lembre-se de que um programa pode ter algum UB e às vezes parece "funcionar").
Quando você realmente precisa de construções orientadas a objetos (em particular herança ), pode usar ponteiros para estruturas e funções relacionadas. Você poderia ter seu próprio maquinário de tabela , ter cada "objeto" começando com um ponteiro para um struct
ponteiro de função contendo. Você aproveita a capacidade de converter um tipo de ponteiro para outro tipo de ponteiro (e do fato de poder converter a partir de um que struct super_st
contenha os mesmos tipos de campo que aqueles que iniciam um struct sub_st
para emular herança). Observe que C é suficiente para implementar sistemas de objetos bastante sofisticados - em particular seguindo algumas convenções -, como o GObject (do GTK / Gnome) demonstra.
Quando você realmente precisa de fechamentos , geralmente os emula com retornos de chamada , com a convenção de que todas as funções que usam um retorno de chamada passam por um ponteiro de função e por alguns dados do cliente (consumidos pelo ponteiro de função quando chama isso). Você também pode ter (convencionalmente) seu próprio fechamento-como- struct
s (contendo algum ponteiro de função e os valores fechados).
Como C é uma linguagem de nível muito baixo, é importante definir e documentar suas próprias convenções (inspiradas pela prática em outros programas C), em particular sobre gerenciamento de memória e, provavelmente, algumas convenções de nomenclatura. É útil ter uma idéia sobre a arquitetura do conjunto de instruções . Não se esqueça que um compilador C pode fazer muitas otimizações no seu código (se você pedir), então não se importe muito em fazer micro-otimizações manualmente, deixe isso para o seu compilador ( gcc -Wall -O2
para compilação otimizada de Programas). Se você se preocupa com benchmarking e desempenho bruto, deve habilitar otimizações (depois que o programa for depurado).
Não se esqueça que às vezes a metaprogramação é útil . Frequentemente, grandes softwares escritos em C contêm alguns scripts ou programas ad-hoc para gerar algum código C usado em outro lugar (e você também pode executar alguns truques sujos do pré-processador C , por exemplo , macros X ). Existem alguns geradores de programas C úteis (por exemplo, yacc ou gnu bison para gerar analisadores, gperf para gerar funções de hash perfeitas, etc ...). Em alguns sistemas (principalmente Linux e POSIX), você pode até gerar algum código C em tempo de execução no generated-001.c
arquivo, compilá-lo em um objeto compartilhado executando algum comando (como gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) em tempo de execução, carregar dinamicamente esse objeto compartilhado usando dlopen& obtenha um ponteiro de função de um nome usando dlsym . Estou fazendo esses truques no MELT (uma linguagem específica de domínio semelhante ao Lisp que pode ser útil para você, pois permite a personalização do compilador GCC ).
Esteja ciente dos conceitos e técnicas de coleta de lixo (a contagem de referência geralmente é uma técnica para gerenciar a memória em C, e é uma forma ruim de coleta de lixo que não lida bem com referências circulares ; você pode ter indicadores fracos para ajudar nisso, mas pode ser complicado). Em algumas ocasiões, você pode considerar usar o coletor de lixo conservador de Boehm .
qux = foo.bar(baz)
se tornamqux = Foo_bar(foo, baz)
.