Capitulo 09 - Classes: Um Exame Mais Profundo Parte 1

Neste Capitulo veremos a utilização de um empacotador pré-processador para evitar em múltiplos erros de definição causados pela inclusão de mais de uma cópia de um arquivo de cabeçalho em um arquivo de código-fonte, no programa Time.h abaixo:

//figura 9.1: Time.h
#ifndef TIME_H
#define TIME_H


//Definição do tipo de dados abstrato Time
class Time
{
     public:
         Time();                              //construtor
         void setTime(int, int, int);       //inicializa hora, minuto, segundo
         void printUniversal();               //imprime no formato de hora militar
         void printStandard();               //imprime no formato de hora padrão

     private:
         int hora;      //0-23
         int minuto;    //0-59
         int segundo;   //0-59

};

#endif


No Próximo programa Time.cpp definimos o escopo de classe no qual acessamos os membros de classe via nome de um objeto, uma referencia a um objeto ou um ponteiro para um objeto.

//Figura 9.2: Time.cpp
#include <iostream>
#include <iomanip>
#include "Time.h" //inclui a definição da classe Time a parti de Time.h

using std::cout;
using std::setfill;
using std::setw;

/*
O construtor de Time inicializa cada membro de dados como zero.
Assegura que todos os objetos Time iniciem em um estado consistente.
*/
Time::Time()
{
    hora = minuto = segundo = 0;
}

/*
configura novo valor de Time utilizando a hora universal; assegura que
os dados permaneçam consistentes configurando valores invalidos como zerovoid
*/
void Time::setTime(int h, int m, int s)
{
    hora = (h >= 0 && h < 24) ? h : 0;        //valida horas
    minuto = (m >= 0 && m < 60) ? m : 0;      //valida minutos
    segundo = (s >= 0 && s < 60) ? s : 0;    //valida segundos
}

//imprime a hora no formato de data/hora universal (HH:MM:SS)
void Time::printUniversal()
{
    cout << setfill('0') << setw(2) << hora << ":"
       << setw(2) << minuto << ":" << setw(2) << segundo;
}

//imprime a hora no formato-padrão de data/hora (HH:MM:SS AM ou PM)
void Time::printStandard()
{
    cout << ((hora == 0 || hora == 12) ? 12 : hora % 12) << ":"
         << setfill('0') << setw(2) << minuto << ":" << setw(2)
         << segundo << (hora < 12 ? " AM" : " PM");
}


No TimeMain programa para testar a classe Time

//figura 9.3: TimeMain.cpp
#include <iostream>
#include "Time.h"
#include "Time.cpp"

using std::cout;
using std::endl;

int main()
{

     Time t;  //instancia o objeto t da classe Time

     //gera saida de valores iniciais do objeto Time t
     cout << "A hora inicial universal = ";
     t.printUniversal(); //00:00:00
     cout << "\nA hora padrao inicial = ";
     t.printStandard(); //12:00:00 AM

     t.setTime(13, 27, 6);

     //gera saida de novos valores do objeto Time t
     cout << "\n\nHora Universal depois de setTime = ";
     t.printUniversal(); //13:27:06
     cout << "\nHora padrao deppois de setTime = ";
     t.printStandard(); //1:27:06

     t.setTime(99, 99, 99); //tenta inicialização invalida

     //gera saida de valores de t depois de especiicar valores inválidos
     cout << "\n\nApos tentar inicialização invalida:\n" << "Hora Universal: ";
     t.printUniversal(); //00:00:00
     cout << "\nHora padrao: ";
     t.printStandard(); //12:00:00 AM
     cout << endl;
     return 0;

}


ao executar pela IDE codeblocks:






ao executar via terminal linux:




//figura 9.4: OperadoresAcesso.cpp
#include <iostream>

using std::cout;
using std::endl;

//definição da classe Count
class Count
{

    public: //dados public são perigosos
         //configura o valor do mmbro de dados private x
         void setX(int value)
         {
             x = value;
         } //fim da função setX

         //imprime o valor do membro de dados private x
         void print()
         {
             cout << x << endl;
         }

    private:
         int x;
};


int main()
{

   Count counter;             //cria objeto contador
   Count *counterPtr = &counter;    //cria ponteiro para contador
   Count &counterRef = counter;     //cria referencia para contador

   cout << "Atribui 7 a x a e imprime usando o nome do objeto: ";
   counter.setX(1);            //configura membro de dados x como 1
   counter.print();         //chama a função-membro print

   cout << "Atribui 8 para x e imprime usando uma referencia: ";
   counterRef.setX(2);       //configura membro de dados x como 2
   counterRef.print();     //chama a função-membro print

   cout << "Atribui 10 para x e imprime usando um ponteiro: ";
   counterPtr->setX(3);     //configura membro de dados x como 3
   counterPtr->print();    //chama a função-membro print

   return 0;

}

ao executar na tela no codeblocks:






ao executar na tela via terminal linux:




As funções de acesso podem ler ou exibir dados. Outra utilização das funções de acesso é testar a verdade ou falsidade de condições. O programa das figuras 9.5-9.7 demonstram a noção de uma função utilitária chamada de função auxiliar. Uma função utilitária não faz parte da interface public de uma classe; em vez disso é uma função-membro private que suporta a oprração das funções public da classe.

//figura 9.5: VendasPessoa.h
#ifndef VENDASP_H
#define VENDASP_H
class VendasPessoa
{
    public:
         VendasPessoa(); //construtor
         void getVendasDeUsuario(); //insere as vendas a partir do teclado
         void setVendas(int, double); //configura vendas de um mes especifico
         void printVendasAnual(); //resume e imprime as vendas

    private:
         double totalVendasAnual(); //prototipo para fnção utilitaria
         double vendas[12]; // 12 estimativas de vendas mensais
}; //fim da classe VendasPessoa

#endif


//Figura 9.6: VendasPessoa.cpp
#include <iostream>
#include <iomanip>

using std::cout;
using std::cin;
using std::endl;
using std::fixed;
using std::setprecision;

//inicializa elementos do array Vendas como 0.0
VendasPessoa::VendasPessoa()
{
    for(int i = 0; i < 12; i++)
    {
        vendas[1] = 0.0;
    }
}

//obtém 12 estimativas de vendas do usuario no teclado
void VendasPessoa::getVendasDeUsuario()
{
    double vendasFigura;

    for(int i = 1; i <= 12; i++)
    {
        cout << "Digite o valor de vendas do mes: " << i << ": ";
        cin >> vendasFigura;
        setVendas(i, vendasFigura);
    }
}


/*
configura uma das 12 estimativas de vendas mensais; a função subtrai
um valor mensal para o subscrito adequado no array vendas
*/

void
VendasPessoa::setVendas(int mes, double valor)
{
    //testa a validade do mes e do valor
    if(mes >= 1 && mes <= 12 && valor > 0)
       vendas[mes - 1] = valor; //ajuda para subscrito 0-11
    else //mes ou valor invalido
       cout << "Mes de vendas invalidas figura" << endl;
}

//imprime o total das vendas anuais(com a ajuda da função utilitaria)
void VendasPessoa::printVendasAnual()
{
    cout << setprecision(2) << fixed
         << "\nO total anual vendas foi: R$"
         << totalVendasAnual() << endl; //chama a função utilitaria
}


//função utlitaria private para somar vendas anuais
double VendasPessoa::totalVendasAnual()
{
    double total = 0.0; //inicializa o total
    for(int i = 0; i < 12; i++)
        total += vendas[i]; //adiciona vendas do mes i ao total

    return total;
}

//Figura 9.7:VendasPessoaMain.cpp
//inclui a dfinição da classe VendasPessoa a partir de VendasPessoa.h
#include "VendasPessoa.h"
#include "VendasPessoa.cpp"

int main()
{
    VendasPessoa v; //cria o objeto VendasPessoa

    v.getVendasDeUsuario(); //anota código sequencial simples;
    v.printVendasAnual();   //nenhuma instrução de controle main
    return 0;
}



ao executar o programa pelo codeblocks:






ao executar o programa via terminal linux:






Definiremos agora os construtores com argumento-padrão aprimorando a classe Time para demonstrar como os argumentos são implicitamente passados para um construtor.

//Figura 9.8: Time2.h
#ifndef TIME2_H
#define TIME2_H


//Definição do tipo de dados abstrato Time
class Time2
{
     public:
         Time2(int = 0, int = 0, int = 0);                              //construtor
         void setTime2(int, int, int);       //inicializa hora, minuto, segundo
         void setHora(int);                  //configura hora(depois da validação)
         void setMinuto(int);                //configura minuto(depois da validação)
         void setSegundo(int);               //configura segundo(depois da validação)

         //funções get
         int getHora();                      //retorna a hora
         int getMinuto();                    //retorna minuto
         int getSegundo();                //retorna o seundo


         void printUniversal();      //gera saida da hora no formato universal de data/hora
         void printStandard();       //imprime no formato de hora padrão

     private:
         int hora;      //0-23(formato de relogio de 24 horas)
         int minuto;    //0-59
         int segundo;   //0-59

};

#endif



O contrutor definido na figura 9.2 inicializou hora, minuto e segundo como 0, isto é meia-noite no horário universal. como outras funções os construtores podem especificar argumentos padrão, e declara o construtor de Time2 para incluir argumentos-padrão, especificando um valor-padrão de zero para cada argumento passado para o construtor.

//figura 9.9: Time2.cpp
#include <iostream>
#include <iomanip>

using std::cout;
using std::setfill;
using std::setw;

/*
O construtor de Time inicializa cada membro de dados como zero.
Assegura que todos os objetos Time iniciem em um estado consistente.
*/
Time2::Time2(int hr, int min, int seg)
{
    setTime2(hr, min, seg); //valida e configura Time2

}

/*
configura novo valor de Time utilizando a hora universal; assegura que
os dados permaneçam consistentes configurandfo valores invalidos como zero
*/
void Time2::setTime2(int h, int m, int s)
{
    setHora(h);        //configura campo private hora
    setMinuto(m);      //configura campo private minuto
    setSegundo(s);    //configura campo private segundo
}


//configura valor de hora
void Time2::setHora(int h)
{
    hora = (h >= 0 && h < 24) ?  h : 0; //valida horas
}

//configura valor de minuto
void Time2::setMinuto(int m)
{
    minuto = (m >= 0 && m < 60) ? m : 0; //valida minutos
}


//configura o valor de segundo
void Time2::setSegundo(int s)
{
    segundo = (s >= 0 && s < 60)  ?  s : 0; //valida segundos
}


//retorna valor de hora
int Time2::getHora()
{
    return hora;
}


//retorna valor de minuto
int Time2::getMinuto()
{
    return minuto;
}


//retorna o valor de segundo
int Time2::getSegundo()
{
    return segundo;
}

//imprime a hora no formato de data/hora universal (HH:MM:SS)
void Time2::printUniversal()
{
    cout << setfill('0') << setw(2) << getHora() << ":"
       << setw(2) << getMinuto() << ":" << setw(2) << getSegundo();
}

//imprime a hora no formato-padrão de data/hora (HH:MM:SS AM ou PM)
void Time2::printStandard()
{
    cout << ((getHora() == 0 || getHora() == 12) ? 12 : getHora() % 12)
         << ":" << setfill('0') << setw(2) << getMinuto()
         << ":" << setw(2) << getSegundo() << (hora < 12 ? " AM" : " PM");
}


//Figura 9.10: Time2Main.cpp
#include <iostream>

using std::cout;
using std::endl;

#include "Time2.h"
#include "Time2.cpp"


//Porgrama pata testar a classe Time simples
int main()
{

     Time2 t1;                //todos os rgumentos convertidos para sua configuracao-padrao
     Time2 t2(2);             //hora especificada; minuto e segundo convertidos para o padrao
     Time2 t3(21, 34);        //hora e minuto especificados; segundo convertido para o padrao
     Time2 t4(12, 25, 42);    //hora, minuto e segundo especificado
     Time2 t5(27, 74, 99);    //valores invalidos especificados


     cout << "Construido com:\n\nt1: todos os argumentos padrao\n ";
     t1.printUniversal(); //00:00:00
     cout << "\n ";
     t1.printStandard(); //12:00:00 AM

     cout << "\n\nt2: hora especificada; minuto e segundo padrao\n ";
     t2.printUniversal(); //02:00:00
     cout << "\n ";
     t2.printStandard(); //2:00:00 AM

     cout << "\n\nt3: hora, e minuto especificado; segundo padrao\n ";
     t3.printUniversal(); //21:34:00
     cout << "\n ";
     t3.printStandard(); //9:34:00 PM

     cout << "\n\nt4: hora, minuto e segundo especificado\n ";
     t4.printUniversal(); //12:25:42
     cout << "\n ";
     t4.printStandard(); //12:25:42 PM

     cout << "\n\nt5: Todos os valores invalidos especiicados\n ";
     t5.printUniversal(); //00:00:00
     cout << "\n ";
     t5.printStandard(); //12:00:00 AM

     cout << endl;
     return 0;

}

ao executar no codeblocks:






ao executar no terminal linux:





definir construtores como argumento-padrão, veremos como os destrutores são utilizados para realizar uma 'faxina de terminação' em um objeto antes dele ser destruido e quando os construtores e destrutores são chamados e a ordem em que são chamados.


//Figura 9.11: ConstrutorDestrutor.h
#include <string>
#ifndef CREATE_H
#define CREATE_H


using std::string;

class ConstrutorDestrutor
{
    public:
         ConstrutorDestrutor(int, string);           //construtor
         ~ConstrutorDestrutor();                     //destrutor

    private:
         int objetoID;      //Numero de ID do objeto
         string mensagem;    //mensagem descrevendo o objeto
};

#endif


//Figura 9.12: ConstrutorDestrutor.cpp
#include <string>
#include <iostream>
#include "ConstrutorDestrutor.h"


using std::cout;
using std::endl;

//construtor
ConstrutorDestrutor::ConstrutorDestrutor(int ID, string mensagemString)
{
    objetoID = ID;                       //configura o numero de ID do objeto
    mensagem = mensagemString;           //confiura mensagem descritiva do objeto

    cout << "Objeto " << objetoID << " correr construtor "
         << mensagem << endl;
}


//destructor
ConstrutorDestrutor::~ConstrutorDestrutor()
{
    //gera saida de nova linha para certos objetos; ajuda a legabilidade
    cout << (objetoID == 1 || objetoID == 6 ? "\n" : "");

    cout << "Objeto " << objetoID << "  correr destruidor "
         << mensagem << endl;
}


//Figura 9.13: ConstrutorDestrutorMain.cpp
#include <iostream>
#include "ConstrutorDestrutor.h"
#include "ConstrutorDestrutor.cpp"

using std::cout;
using std::endl;

void criar(void); //prototipo

ConstrutorDestrutor primeiro(1, "(Global antes do main)" ); //objeto global

int main()
{
    cout << "\nFUNCAO MAIN: COMECO DE EXECUCAO" << endl;
    ConstrutorDestrutor segundo(2, "(Local automatic em main)" );
    static ConstrutorDestrutor terceiro(3, "(Local static em main)" );

    criar();  //chama funcao para criar objetos

    cout << "\nCRIANDO FUNCAO: INICIO EXECUCAO" << endl;
    ConstrutorDestrutor quarto(4, "(Local automatico main)" );
    cout << "\nFUNCAO MAIN: FINALIZA EXECUCAO" << endl;
    return 0;
}

//funcao para criar objetos
void criar(void)
{
    cout << "\nCRIANDO FUNCAO: INICIO EXECUCAO" << endl;
    ConstrutorDestrutor quinto(5, "(Criando local automaticamente)");
    static ConstrutorDestrutor sexto(6, "(Criando local estatico)");
    ConstrutorDestrutor setimo(7, "(Criacao local automatica)");
    cout << "\nCRIANDO FUNCAO: FINALIZA EXECUCAO" << endl;
}

ao executar via codeblocks:


ao executar vi terminal linux:







Estudo de caso de uma classe Time: uma armadilha sutil:
os erros de lógica que podem ocorrer quando uma funcao-membro public de uma classe retorna uma referencia a dados private.

/*
Estudo de caso de uma classe Time: uma armadilha sutil -
retornar uma referencia a um membro de dados private

Figura 9.14: Time3.h
Declaracao da classe Time3.
Funcoes-membro definidas em Time.cpp
*/

//impede multiplas inclusoes de arquivo de cabecalho
#ifndef TIME3_H
#define TIME3_H


class Time3
{
      public:
           Time3(int = 0, int = 0, int = 0);
           void setTime3(int, int, int);
           int getHora();
           int &badSetHora(int); //retorno de referencia PERIGOSO

      private:
           int hora;
           int minuto;
           int segundo;
};

#endif

/*
Estudo de caso de uma classe Time: uma armadilha sutil -
retornar uma referencia a um membro de dados private

Figura 9.15: Time3.cpp
Definicoes de funcao-membro para a classe Time3.
*/

/*
funcao constructor para inicializar dados private;
chama a funcao-membro setTime3 para configurar variaveis;
valores-padrao sao 0 (ver definicao de classe)
*/

Time3::Time3(int hr, int min, int seg)
{
    setTime3(hr, min, seg);
}

//configura valores de hora, minuto e segundo
void Time3::setTime3(int h, int m, int s)
{
    hora = (h >= 0 && h < 24) ? h : 0;        //valida horas
    minuto = (m >= 0 && m < 60) ? m : 0;      //valida minutos
    segundo = (s >= 0 && s < 60) ? s : 0;     //valida segundos
}

//retorna valor de hora
int Time3::getHora()
{
    return hora;
}

/*
PRATICA DE PROGRAMACAO RUIM:
Retorna uma referencia a um membro de dados private.
*/
int &Time3::badSetHora(int hh)
{
    hora = (hh >= 0 && hh < 24) ? hh : 0;
    return hora; //retorno de referencia PERIGOSO
}



/*
Estudo de caso de uma classe Time: uma armadilha sutil -
retornar uma referencia a um membro de dados private

Demonstrando uma funcao-membro public que
retorna uma referencia a um mebro de dados private.
*/

#include <iostream>
#include "Time3.h"
#include "Time3.cpp"


using std::cout;
using std::endl;

int main()
{
    Time3 t; //cria o objeto Time3

    //incializa horaRef com a referencia retornado por badSetHora
    int &horaRef = t.badSetHora(20); //20 e a valida hora

    cout << "Valida hora depois de modificado: " <<horaRef;
    horaRef = 30;  //use horaRef em set valor invalido em Time3 objeto t
    cout << "\n Invalido hora antes notificada: " << t.getHora();

    /*
    chamada de funcao perigosa que retorna
    com valor de referencia a ser usado
    */
    t.badSetHora(12) = 74; //atribui outro valor invalido em hora

    cout << "\n\n********************************************************\n"
         << "PROGRAMACAO PRATICA!!!!!!!!!!!!\n"
         << "t.badSethora(12) valor invalido em hora: "
         << t.getHora()
         << "\n**********************************************************" << endl;

    return 0;

}

ao executar no codeblocks:


ao executar via terminal linux:







Atribuir os membros de dados de um objeto aqueles de outro objeto por atribuição-padrão de membro a membro.


//Figura 9.17: Date.h
#ifndef DATE_H
#define DATE_H


//definicao da classe Date
class Date
{
      public:
           Date(int = 1, int = 1, int = 2000);   //construtor-padrao
           void print();

      private:
           int mes;
           int dia;
           int ano;
};

#endif


//Figura 9.18: Date.cpp
#include <iostream>

using std::cout;
using std::endl;

//construtor Date (deve fazer uma verificao de intervalo)
Date::Date(int d, int m, int y)
{
    dia = d;
    mes = m;
    ano = y;
}

//imprime Date no formato DD/MM/YYYY
void Date::print()
{
    cout << mes << '/' << dia << '/' << ano;
}


//Figura 9.19: DateMain.cpp
#include <iostream>
#include "Date.h"      //inclui a definicao da classe Date a partir de Date.h
#include "Date.cpp"    //inclui a definicao da funcao Date a partir de Date.cpp

using std::cout;
using std::endl;

int main()
{
    Date data1(8, 24, 2010);
    Date data2;

    cout << "data1 = ";
    data1.print();
    cout << "\ndata2 = ";
    data2.print();

    data2 = data1; //atribuicao padrao de membro a membro

    cout << "\n\nApos a atribuicao de membro padrao, data2 = ";
    data2.print();
    cout << endl;
    return 0;

}

ao executar no codeblocks:






ao executar via terminal linux:







Aqui terminanos mais este capitulo, e até a proxíma





























 












































Comentários

Postagens mais visitadas