• Nenhum resultado encontrado

Diretivas #ifdef |#ifndef –#endif

Se vocˆe ´e curioso, certamente vocˆe j´a abriu um arquivo de cabe¸calho para ver o que tem dentro dele. De cara, vocˆe viu v´arios testes condicionais avali- ando o ambiente de programa¸c˜ao.

Quando um arquivo de cabe¸calho ´e criado, ´e comum definir-se um s´ımbolo que o identifique. O s´ımbolo pode ser qualquer string v´alida em C. De praxe, o s´ımbolo usado ´e o nome do arquivo de cabe¸calho em letras mai´usculas com o car´acter sublinha (“ ”) no lugar do ponto da extens˜ao. Por exemplo, se o arquivo de cabe¸calho se chama “MeuCabecalho.h”, o candidato para s´ımbolo seria “#define MEUCABECALHO H ”.

Como foi apresentado nas se¸c˜oes sobre fun¸c˜oes e diretiva #include, o ar- quivo de cabe¸calho cont´em prot´otipos de fun¸c˜oes, estruturas de dados, de- fini¸c˜oes de tipo com typedef ’s, defini¸c˜oes de macros e algumas coisas mais. ´E comum estruturar-se a programa¸c˜ao em v´arios arquivos, tanto de c´odigo-fonte como de cabe¸calho, segundo uma l´ogica definida pelo programador. ´E prov´avel tamb´em que um ou mais arquivos de cabe¸calho contenham defini¸c˜oes b´asicas

6.4. DIRETIVAS #IFDEF|#IFNDEF–#ENDIF 81 que outros arquivos de cabe¸calho e de c´odigo-fonte utilizam. Neste cen´ario, um problema corriqueiro ´e a duplicidade de defini¸c˜oes de macros, prot´otipos e outras informa¸c˜oes, principalmente no caso de arquivos de cabe¸calho inclu´ırem outros arquivos de cabe¸calho atrav´es da diretiva #include.

Para clarear a situa¸c˜ao, imagine que trˆes arquivos de cabe¸calho chamados “base.h”, “modulo.h” e “fase.h” tenham os seguintes trechos de c´odigo:

C´odigo 6.4: base.h # define q u a d r a d o ( a ) (( a )*( a )) typedef struct { double x , y ; } upla ; C´odigo 6.5: modulo.h # include " base . h " /* p r o t o t i p o da funcao modulo () */

double modulo ( upla a );

C´odigo 6.6: fase.h

# include " base . h "

/* p r o t o t i p o da funcao fase () */

double fase ( upla a );

e que “modulo.h” e “fase.h” sejam chamados pelo c´odigo-fonte “exemploX.c”: C´odigo 6.7: exemplo29.c

# include < stdio .h >

# include < math .h >

# include " base . h " /* por causa do tipo upla

e da macro q u a d r a d o ( a ) */

# include " modulo . h " /* por causa do p r o t o t i p o */

# include " fase . h " /* por causa do p r o t o t i p o */

double modulo ( upla a ) {

return sqrt ( q u a d r a d o ( a . x )+ q u a d r a d o ( a . y )); }

double fase ( upla a ) {

return atan2 ( a .y , a . x ); }

upla c ;

c . x = 1; c . y = 1;

printf (" modulo = % lf \ tfase = % lf \ n ",

modulo ( c ) , fase ( c ));

return 0; }

O compilador, ao processar o arquivo de c´odigo-fonte “exemploX.c”, come¸car´a detectando e incluindo o arquivo de cabe¸calho “math.h”. Depois, incluir´a “base.h” que define o tipo “upla”. A pr´oxima inclus˜ao ´e o arquivo de cabe¸calho “modulo.h” que cont´em, tamb´em, a inclus˜ao do arquivo de cabe¸calho “base.h”, que j´a foi processado pelo compilador. Quando o compilador abrir pela segunda vez o arquivo “base.h”, ele encontrar´a a declara¸c˜ao do tipo “upla”, que j´a foi definido na primeira leitura do arquivo “base.h”. Como medida defensiva, o compilador gera um erro e aborta o processo de compila¸c˜ao.

Para evitar duplicidades de declara¸c˜oes durante o processo de compila¸c˜ao, cria-se s´ımbolos para cada arquivo de cabe¸calho: no arquivo “base.h”, cria- se o s´ımbolo “#define BASE H”; no arquivo “modulo.h”, o s´ımbolo “#define MODULO H”; e no arquivo “fase.h”, o s´ımbolo “#define FASE H”. Al´em disso, introduz-se as diretivas #ifndef para controlar a o reprocessamento dos con- te´udos dos arquivos. Os arquivos ficam da seguinte forma:

C´odigo 6.8: base.h # ifndef BASE_H # define BASE_H # define q u a d r a d o ( a ) (( a )*( a )) typedef struct { double x , y ; } upla ; # endif C´odigo 6.9: modulo.h # ifndef M O D U L O _ H # define M O D U L O _ H

6.4. DIRETIVAS #IFDEF|#IFNDEF–#ENDIF 83

double modulo ( upla a );/* p r o t o t i p o da funcao modulo () */

# endif

C´odigo 6.10: fase.h

# ifndef FASE_H

# define FASE_H

# include " base . h " /* por causa de upla */

double fase ( upla a ); /* p r o t o t i p o da funcao fase () */

# endif

Ent˜ao, quando “exemploX.c” ´e compilado, o compilador carrega o conte´udo do arquivo “base.h”. A primeira pergunta que o compilador faz ´e: “O s´ımbolo BASE H j´a foi definido?”. Como ´e a primeira vez que o arquivo est´a sendo acessado, a resposta ´e n˜ao. Se o s´ımbolo “BASE H ” n˜ao est´a definido, ent˜ao o compilador entra no bloco e cria o s´ımbolo “BASE H ” atrav´es do comando “#define BASE H”.

Ao terminar o processamento de “base.h”, o compilador passa para o pr´oximo #include (“#include "modulo.h"”). Ao abrir o arquivo “modulo.h”, o compilador encontra o #include do arquivo “base.h”. O compilador, ent˜ao, carrega o arquivo “base.h” e faz novamente a pergunta: “O s´ımbolo BASE H j´a foi definido?”. Nesta caso, j´a. Ent˜ao, a diretiva #ifndef falha e o conte´udo de “base.h” n˜ao ´e mais carregado, pois j´a est´a na mem´oria do computador.

O uso do #ifndef ´e muito pr´atico, pois, se a ordem do arquivos de cabe¸calho forem alterados, o conte´udo de “base.h” tamb´em n˜ao ser´a recarregado. Uma vez lido, as pr´oximas solicita¸c˜oes n˜ao s˜ao mais atendidas.

7

Organiza¸c˜ao da Programa¸c˜ao em C

Algum texto

8

Classes e Objetos

A linguagem C segue o modelo (paradigma) da programa¸c˜ao estruturada. Ela se caracteriza principalmente na organiza¸c˜ao do c´odigo fonte na forma de fun¸c˜oes. Por isso ela ´e classificada como uma linguagem procedural (que usam fun¸c˜oes e procedimentos). A organiza¸c˜ao baseada em fun¸c˜oes e proce- dimentos permite que o usu´ario reutilize seus recursos j´a programados sempre que precisar, bastando, para isso, chamar a fun¸c˜ao ou sub-rotina necess´aria. Na programa¸c˜ao estruturada, a solu¸c˜ao dos problemas ´e obtida atrav´es da execu¸c˜ao da sequˆencia de instru¸c˜oes implementadas no c´odigo. Portanto, as linguagens estruturadas s˜ao ditas serem orientadas a fluxo de execu¸c˜ao.

Mas nem todos os problemas s˜ao modelados facilmente atrav´es do mo- delo de programa¸c˜ao estruturada. A natureza de alguns problemas exige uma abordagem diferente. Um exemplo simples est´a na aplica¸c˜ao da computa¸c˜ao para reprodu¸c˜ao de sistemas, ou seja, simula¸c˜ao. Neste tipo de problema, v´arias partes do sistema real est˜ao operando simultaneamente e cada parte do sistema possui caracter´ısticas pr´oprias. A colabora¸c˜ao entre as partes ´e que “materializam” a solu¸c˜ao do problema.

Imagine uma c´elula. Cada estrutura da c´elula faz uma coisa diferente, mas tire uma delas para vocˆe ver o que acontece... Ent˜ao, cada parte, cada elemento ´e essencial para o funcionamento do todo, mas a parte, o elemento, n˜ao ´e o todo. O importante neste paradigma ´e a colabora¸c˜ao entre as partes, cada um fazendo o que sabe e colaborando com as demais. E a colabora¸c˜ao se d´a atrav´es de trocas de mensagens. No caso da c´elula, as mensagens s˜ao as substˆancias qu´ımicas liberadas por cada estrutura. Essas substˆancias provocam altera¸c˜oes no funcionamento das outras estruturas produzindo a¸c˜oes diferentes.

Se fˆossemos simular uma c´elula, partir´ıamos do projeto dos elementos cons- tituintes dela, pois cada uma possui caracter´ısticas e habilidades particulares. Podemos olhar para cada elemento projetado como um objeto, algo que possui propriedades e capacidades. Depois, colocar´ıamos estes objetos juntos numa caixa e a “ligar´ıamos”. Imaginando que cada objeto come¸casse a interagir com

as demais, a nossa c´elula simulada come¸caria a funcionar.

A moral que espero que seja observado aqui, neste exemplo, ´e que, se os objetos forem programados e se eles cooperarem entre si, o nosso problema est´a resolvido. Esta ´e a essˆencia do paradigma da programa¸c˜ao orientada a objeto. Agora, entre a abstra¸c˜ao e a especifica¸c˜ao, a distˆancia ´e grande. Partindo-se da linguagem estruturada C, propˆos-se, no final da d´ecada de 70 e in´ıcio dos anos 80, uma complementa¸c˜ao das capacidades da linguagem de forma que ela suportasse o modelo de programa¸c˜ao orientada a objeto. Esta complementa¸c˜ao, que no jarg˜ao da ciˆencia da computa¸c˜ao se chama superset, deu origem `a linguagem de programa¸c˜ao C++ que, na verdade, ´e a mesma linguagem estruturada C acrescida de novas capacidades. Por isso, tem muita gente que usa o compilador de C++ e acha que est´a fazendo programa¸c˜ao orientada a objeto, mas est´a na verdade programando de forma estruturada, usando somente os recursos da linguagem C. N˜ao ´e pelo fato de usar instru¸c˜oes pr´oprias do C++ que transforma a programa¸c˜ao em orientada a objeto. ´E necess´ario que a l´ogica, o projeto, sejam baseados no modelo de programa¸c˜ao orientado a objeto. Ent˜ao, n˜ao se iludam. Querem programar orientado a objeto? Aprendam primeiro o que ´e programa¸c˜ao orientada a objeto.

Como este material n˜ao tem a inten¸c˜ao de ensinar o que ´e programa¸c˜ao orientada a objeto, mas, simplesmente, introduzir os elementos e os recursos de programa¸c˜ao da linguagem C++, fica o compromisso de cada leitor de correr atr´as do conhecimento necess´ario para aprender a programar usando orienta¸c˜ao a objeto. O que ser´a apresentado aqui ´e a conceitua¸c˜ao de classes e objetos, suas propriedades e a sintaxe da linguagem C++ (que ´e tudo que j´a foi visto at´e aqui mais um pouquinho).

Ent˜ao, vamos l´a.

8.1

Encapsulamento de Atributos e M´etodos

As classes s˜ao modelos de objetos. Funcionam como projetos de algo que se materializar´a em um futuro pr´oximo, os objetos propriamente ditos. Em uma classe, podem existir atributos e m´etodos, onde os atributos s˜ao as ca- racter´ısticas est´aticas que diferenciar˜ao um objeto de outro e os m´etodos s˜ao as habilidades que cada objeto poder´a exercer.

Um exemplo simples: quando pensamos num ve´ıculo, imaginamos um ob- jeto com portas, rodas, motor, cor, marca, categoria, etc. Todo ve´ıculo tem estas coisas, estes atributos, mas, ainda assim, somos capazes de distinguir os ve´ıculos. Uns tem duas portas, outros quatro. Uns s˜ao vermelhos, outros pretos. Tem ve´ıculo de passeio e tem ve´ıculo de carga e transporte. Quando atribu´ımos valores, conte´udos, aos atributos de uma classe, geramos um objeto desta classe. Todo objeto ´e particular e toda classe pode gerar v´arios objetos. Um Pegeout 206 e um Renout Clio s˜ao da classe ve´ıculo e s˜ao objetos distintos.

8.2. VISIBILIDADE DE IMPLEMENTAC¸ ˜AO 89 A outra caracter´ıstica das classes s˜ao os m´etodos. Como foi dito, m´etodo ´e toda habilidade que a classe possui. ´E sua capacidade de fazer coisas. A implementa¸c˜ao dos m´etodos de uma classe ´e idˆentica `a implementa¸c˜ao de uma fun¸c˜ao. Um m´etodo pode receber dados e devolver dados. Estes dados que “v˜ao e vem” atrav´es dos m´etodos s˜ao as mensagens. ´E atrav´es destas trocas de mensagens que um programa orientado a objeto funciona.

Em C++, uma classe ´e implementada da mesma forma que uma estrutura do tipo struct. Ela possui campos (os atributos da classe) e incorpora fun¸c˜oes (os m´etodos da classe), tudo na mesma estrutura. Esta propriedade se chama encapsulamento. A declara¸c˜ao de uma classe usa a palavra reservada class:

class Nome_da_Classe {

/* declara¸c~ao dos atributos */ char dado1;

unsigned dado2; struct estrutura1 { } dado3;

/* declara¸c~ao dos m´etodos */ void medodo1(void);

unsigned metodo2(void); void metodo3(float arg1); };

Os atributos s˜ao dado1, dado2 e dado3 dos tipos char , unsigned e struct es- trutura1, respectivamente, e os m´etodos s˜ao metodo1(void), metodo2(void) e metodo3(float arg1).

Os tipos intr´ınsecos s˜ao classes.

Documentos relacionados