Contents

PROGRAMAÇÃO ORIENTADA A OBJETOS - CONCEITOS BÁSICOS


PROGRAMAÇÃO ORIENTADA A OBJETOS - CONCEITOS BÁSICOS

TIPOS ABSTRATO DE DADOS


Um tipo abstrato de dado é um tipo definido pelo programador com um conjunto de valores e uma coleção de operações sobre estes valores. As operações devem ser consistentes com os tipos dos valores.
Para a implementação de um tipo abstrato de dado, o programador deve escolher uma representação de dados de um dado abstrato usando os tipos de dados existentes e, implementar as operações permitidas sobre estes dados com as instruções da linguagem de programação desejada.

ORIENTAÇÃO A OBJETOS

A idéia fundamental de linguagens orientadas a objetos é a possibilidade de combinar num único registro campos que conterão dados e campos que são funções para operar os campos de dados do registro. Um tipo abstrato de dado que suporta este conceito é a classe.

CLASSE


Uma classe é ponto de partida inicial para se desenvolver um programa em linguagens orientadas à objetos.
Uma classe é um de tipo abstrato de dados. Abaixo, relacionamos os componentes de uma classe (não é obrigatório conter todos na definição de uma classe) :


Dados públicos;
Dados privados;
Dados protegidos;
Funções-membro;
Construtores;
Destrutores;
Classes Amigas.

Abaixo, é apresentado um exemplo de uma classe em C++ e seus componentes :
class emp 
{
      private :
                   int empno;
                   char ename[10 + 1];
                   char job[9 + 1];
                   int mgr;
                   long int hiredate;
                   long int sal;
                   long int comm;
                   int deptno;
      public : 
                   emp(); // construtor
                   emp(int emp, char nome[10 + 1], char j[9 + 1], int m,
                        long int h, long int s, long int c, int d); 
                       ~emp(); // destrutor , executa a exclusão
                   int inclusão();
                   void alteração();
                   void consulta();
                   void tela();
                   void menu();
                   int le_disco(fstream *fio);
                   int grava_disco(fstream *fio); 
                   int abre_arq(fstream *fio); 
                   long num_reg(fstream *fio); 
}; 

DADOS PRIVADOS


Os dados privados são acessados somente pelas funções-membro da classe. Dizemos que os dados privados são ocultos para os dados não pertencentes a classe.
Exemplo : Na classe emp declarada abaixo, todas as variáveis foram declaradas como dados privados. Isto é feito para garantir maior integridade e segurança aos dados manipulados de um objeto.

class emp 
{
      private :
                   int empno;
                   char ename[10 + 1];
                   char job[9 + 1];
                   int mgr;
                   long int hiredate;
                   long int sal;
                   long int comm;
                   int deptno;
};

DADOS PÚBLICOS


Dados públicos podem ser acessados por qualquer objeto de uma classe.
Abaixo é descrito um exemplo de dados públicos.
Dados públicos, normalmente, são as funções-membro de uma classe.

class emp 
{
      public : 
                   emp(); // construtor
                   emp(int emp, char nome[10 + 1], char j[9 + 1], int m,
                        long int h, long int s, long int c, int d); 
                   ~emp(); // destrutor , executa a exclusão 
                   int inclusão();
                   void alteração();
                   void consulta();
                   void tela();
                   void menu();
                   int le_disco(fstream *fio);
                   int grava_disco(fstream *fio); 
                   int abre_arq(fstream *fio); 
                   long num_reg(fstream *fio); 
}; 

DADOS PROTEGIDOS


Ao invés de declararmos os dados de uma classe como privados podemos declará-los como protegidos. A vantagem de utilizar isto é que os dados declarados como protegidos podem ser acessados em caso de herança pela classe derivada e se forem declarados como privados a classe derivada não terá acesso a eles.

class BASE
{
   protected : Int secreto;   
   private : int ultra_secreto; 
   public : int publico;
};
class DERIV1 : public BASE 
{ 
   public :
                int a = secreto; // ok
                int b = ultra_secreto; // erro : não-acessível 
                int c = publico // ok 
};
class DERIV2 : private BASE 
{
   public :
                int a = secreto; // ok
                int b = ultra_secreto; // erro : não-acessível
                int c = publico // ok 
} ;

INSTÂNCIA DE CLASSE


É importante salientar que uma classe é um tipo abstrato de dado e não um objeto. Quando criamos uma variável do tipo da classe declarada, criamos um objeto desta classe.

Exemplo : emp obj1; ( a variável obj1 é um objeto da classe emp)

FUNÇÃO-MEMBRO


Nós definimos as funções-membro dentro de uma classe e, somente os objetos destas classe poderão ter acesso as mesmas. São o único meio de acesso aos campos de dados ou também chamados dados privados. Abaixo é descrito um exemplo da função-membro tela declarada na classe emp. Funções-membro também são chamadas de métodos.
Exemplo :

void emp::tela()
{
    clrscr();
    gotoxy(30,6);
    cout << "Cadastro de Empresas";
    gotoxy(10,8); 
    cout << "Código Empresa : ";
    gotoxy(10,10); 
    cout << "Nome Empresa : "; 
    gotoxy(10,12); 
    cout << "Cargo : "; 
    gotoxy(10,14); 
    cout << "Código Gerente : "; 
    gotoxy(10,16); 
    cout << "Data : "; 
    gotoxy(10,18); 
    cout << "Salário : "; 
    gotoxy(10,20); 
    cout << "Comissão : "; 
    gotoxy(10,22); 
    cout << "Departamento : ";
};

CHAMADA A FUNÇÕES-MEMBRO


As funções-membro só podem ser chamadas quando associadas ao objeto específico pelo operador ponto. Uma função-membro age sobre um objeto em particular e não sobre a classe como um todo. Um exemplo : Se quisermos chamar a função-membro inclusão da classe emp, primeiro temos que criar um objeto desta classe e depois chamar a função-membro, como segue :

emp obj.;
obj.inclusao();
A instrução de chamada a uma função-membro é denominada MENSAGEM.

DEFINIÇÃO DE FUNÇÕES-MEMBRO


As funções-membro podem ser definidas dentro da própria declaração da classe quanto fora dela. Se for feita fora da definição da classe, devemos declarar dentro da classe o protótipo da função-membro. Podemos então, declarar a função-membro em qualquer parte do programa. Quando a declararmos, deveremos colocar antes do nome da função-membro nome da classe seguido do operador "::" para identificar a qual classe ela pertence.
Exemplo : Se quiséssemos declarar a função-membro inclusão da classe emp em qualquer lugar do programa devemos declarar como segue :

int emp::inclusao(parâmetros)

CONSTRUTOR


Construtor é uma função-membro que é executada quando é criado uma instância de classe. Isto garante a inicialização de uma instância de classe. O nome do construtor é o mesmo que o nome da classe. Podemos declarar um construtor de duas maneiras:

1. Apenas com parênteses e sem parâmetros;
2. Com parênteses e parâmetros.
O próprio compilador define qual construtor será chamado (se os dois forem declarados) no momento em que uma instância de classe está sendo criada. Um construtor nunca é chamado por um objeto da classe, mas sempre quando é criada uma instância dessa classe. O construtor não deve retornar nenhum valor. O motivo é que ele é chamado diretamente pelo sistema e não temos como recuperar um valor de retorno.

Exemplo do construtor da classe emp sem parâmetros :
emp::emp() // construtor 
{ 
    empno = 0;
    ename[0] = '\0';
    job[0] = '\0'; 
    mgr = 0; 
    hiredate = 0;
    sal = 0; 
    comm = 0;
    deptno = 0;
}
Exemplo do construtor da classe emp com parâmetros :
emp::emp( int emp, char nome[10 + 1], char j[9 + 1], int m, long int h,
long int s, long int c, int d)
{
    empno = emp; 
    strcpy(ename,nome); 
    strcpy(job,j); 
    mgr = m; 
    hiredate = h;
    sal = s; 
    comm = c; 
    deptno = d;
};

DESTRUTOR


Destrutor é uma função-membro que é executada quando é destruída uma instância de classe. O nome do destrutor é o mesmo que o nome da classe precedido do caracter `~'. Abaixo é descrito um exemplo da classe emp que diminui o valor do salário em um cada vez que um objeto é destruído.
emp::~emp() // destrutor , executa a exclusão { sal - -; }

CLASSES INVARIANTES


Uma classe invariante é uma declaração sobre o corrente estado de uma instância de uma classe. Tipos invariantes referem-se tipicamente somente para os dados membros de uma classe. Todas as funções-membro da classe devem cooperar para preservar o estado da classe invariante. Uma classe invariante é uma pós-condição implícita para cada função-membro. E, é também uma pré-condição implícita para a função-membro exceto os construtores. Todas classes devem providenciar um jeito de inicializar suas classes invariantes. A estrutura de um construtor é o local mais apropriado. Um construtor é chamado quando uma classe é criada, antes que o usuário possa chamar qualquer outra função-membro da classe. Entretanto, os comandos do construtor devem inicializar os dados de uma instância de classe mantendo o resultado da classe invariante sempre verdadeiro quando o construtor retornar o controle do programa.

ENCAPSULAMENTO DE DADOS


O encapsulamento de dados em uma classe são os dados que são escondidos, ou seja, os dados declarados como private. Com isto, somente funções-membro podem acessar os dados declarados como private e não qualquer variável declarada como instância de uma classe. Um exemplo do encapsulamento de dados é descrito abaixo através da declaração de variáveis da classe emp como dados privados.

class emp 
{
      private :
                   int empno;
                   char ename[10 + 1];
                   char job[9 + 1];
                   int mgr;
                   long int hiredate;
                   long int sal;
                   long int comm;
                   int deptno;
};

POLIMORFISMO


A palavra polimorfismo em Programação orientada a objetos assume o sentido de que com um único nome para uma função-membro podemos definir várias funções distintas. Duas ou mais funções-membro podem ter o mesmo nome, mas um código independente. A situação anterior é bastante utilizada em classes derivadas à partir de herança simples ou múltipla.

HERANÇA


A herança é um recurso muito poderoso da programação orientada a objetos. Herança é o processo pelo qual criamos novas classes à partir de classes existentes. A herança nos permite relacionar classes que contém parte ou totalmente dos dados relacionados entre si. Um exemplo clássico de herança é representado na figura abaixo:


A sintaxe da criação de uma classe através de herança é a seguinte :

class < nome classe > : < nome da classe base >

Após a criação de uma classe derivada, esta tem acesso a todos os dados públicos da classe base. Todos os métodos declarados como públicos da classe base estão automaticamente disponíveis para a classe derivada. Se uma classe derivada quiser acessar os dados privados da classe base não terá acesso. Para possibilitar este acesso, os dados privados na classe base devem ser declarados como protegidos. A classe derivada pode acessar os métodos da classe base como segue abaixo : · Após a declaração de um método na classe derivada, coloca-se o operador ":" e o nome do método da classe base; como no exemplo abaixo :

class janela
{
     protected :int linicio, cinicio, lfim, cfim; 
     public : janela();
              janela(int li, int ci, int lf, int cf);
              void box(char modo[] = "[]|-=+|");
};
class window : public janela // classe derivada (herança) 
{ public : window(): janela() {}; window(int li, int ci, int lf, int cf) : janela(li,cf,lf,cf){}; void cls(); void cursor(char lin, char col); void centra(char lin, char s[]) ; };

No exemplo acima, a classe derivada "window" possui em seu construtor uma chamada para o contrutor da classe base janela.

Podemos também chamar um método da classe base como se fossemos chamar um método desta mesma classe. No exemplo acima, poderíamos ter a seguinte situação : window obj1; obj1.box; Na situação acima, é chamado o método "box" da classe window, mas ele não existe. O compilador então verifica se ele existe na classe base, se existe, o executa.

Abaixo, segue um exemplo de criação de classe através de herança.
Class conta 
{
   private : 
                 char nome[40]; // nome do cliente 
                 int nconta; // número da conta 
                 float saldo; // saldo da conta
   public :
                 void getdata(); 
                 void putdata();
                 float Saldo();
};
class ContaSimples : public conta {};
class ContaEspecial : public conta
{
   private :float limite;
   public :
                 void getdata();
                 void putdata();
};
class Poupanca : public conta 
{ 
private : float taxa; 
public : 
                 void getdata() { conta::getdata(); cout << " Taxa:";
                                         cin >> taxa; }
                 void putdata() { conta::putdata(); cout << "\n Taxa:" <<
                                        taxa; cout << "\nSaldo Total: " << (Saldo() * taxa);}
};
No exemplo acima, declaramos uma classe conta (classe base) e declaramos as classes conta_especial, conta_simples e poupança como classes derivadas da classe conta. Quando declaramos uma classe como derivada de outra, a classe derivada herda todas as características da classe-base (este processo recebe o nome de reutilização do código). A classe derivada pode acessar todos os dados públicos e privados da classe-base. Além do que, pode alterar estes dados, isto é, pode acrescentar novos campos de dados, pode reescrever um método da classe-base com o mesmo nome e alterar o seu conteúdo.
O uso de uma biblioteca de classes oferece uma grande vantagem sobre o uso de uma biblioteca de funções : o programador pode criar classes derivadas de classes bases de bibliotecas. Isto significa que, sem alterar a classe base, é possível adicionar características diferentes que a tornarão capaz de executar exatamente o que desejamos.
O uso de classes derivadas aumenta a eficiência da programação pela não necessidade da criação de códigos repetitivos.
A uma função de biblioteca não podemos adicionar outras implementações a não ser que ela seja reescrita ou que tenhamos seu código fonte para alterá-la e recompilá-la.

HERANÇA PÚBLICA E PRIVADA


Quando criamos uma classe derivada com a clausula "public", estamos dizendo que os dados públicos da classe base serão dados públicos na classe derivada e, os dados protegidos serão os dados protegidos da classe derivada. A classe derivada não terá acesso aos dados privados. Podemos criar uma classe com a clausula "private", com isso tanto os dados públicos como protegidos da classe base serão dados privados da classe derivada. Com isso, a classe derivada não terá acesso a nenhum dado da classe base.

class BASE
{
    protected : Int secreto;   
    private : int ultra_secreto; 
    public : int publico;
};
class DERIV1 : public BASE 
{ 
    public :
                int a = secreto; // ok
                int b = ultra_secreto; // erro :não-acessível 
                int c = publico // ok 
};
class DERIV2 : private BASE 
{
    public :
                int a = secreto; // ok
                int b = ultra_secreto; // erro :não-acessível
                int c = publico // ok 
} ;

REESCREVER FUNÇÕES-MEMBRO DE CLASSES BASE


É possível a criação de funções-membro na classe derivada que tenha o mesmo nome de uma função-membro da classe base. Com isto, podemos chamar a função-membro da classe base através do operador de escopo "::" e, construirmos este procedimento com o que queremos.
Exemplo :

const TAM = 80;
class BasAg 
{
     protected : 
                      char nome[TAM]; 
                      char numag[4]; 
     public : 
                     BasAg() { nome[0] = '\0'; numag[0] = '\0'; } 
                     BasAg(char n[],char ng[]) {}
                     void print(){}                     
};
class Agente : public BasAg // herança ou classe derivada { protected : float altura; int idade; public : Agente() : BasAg() { altura = 0; idade = 0; } Agente(char n[], char ng[], float a, int i) : BasAg(n,ng) { altura = a; idade = i; } void print();
};
void main() { Agente agente("Daniel","1",1.78,21); agente.print(); }
No exemplo acima, o método "print()" da classe derivada agente é reescrita com o mesmo nome do método da classe base e, ainda, chama o método "print()" da classe base BasAg através do operador de escopo "::". Quando for executado o comando "agente.print()" do exemplo acima, o compilador executará o método print() da classe agente. Mas, o primeiro comando deste método é chamar o método de mesmo nome da classe base, o compilador executa este método e, após os comandos do método da classe derivada.

HERANÇA MÚLTIPLA


Quando uma classe herda as características de mais de uma classe-base. Abaixo, temos o exemplo de herança múltipla. Declaramos as classes simples Cadastro, Imóvel e Tipo. Declaramos a classe Venda como herança múltipla das três anteriores.

class Cadastro
{
   private :
                     char nome[30], fone[20];
   public :                      
                     Cadastro();
                     void getdata();
                     void putdata(); 
};
class Imóvel 
{ 
   private :
                     char end[30], bairro[20]; 
                     float AreaUtil, AreaTotal; 
                     int quartos; 
   public :
                     Imóvel();
                     void getdata();
                     void putdata();
};
class Tipo 
{ 
   private : 
                     char tipo[20]; // Residencial, Loja, Galpão... 
   public : 
                     Tipo();
                     void getdata();
                     void putdata();
};
class Venda : private Cadastro,Imovel,Tipo 
{ 
  private : 
                     float valor; 
  public : 
                     Venda() : Cadastro(), Imóvel(), Tipo();
                     void getdata();
                     void putdata(); 
};

FUNÇÕES VIRTUAIS


São utilizadas quando queremos fazer referência através de uma matriz de ponteiros para uma classe base que contém várias classes derivadas com o objetivo de acessar um mesmo método de cada classe derivada. Para utilizarmos este recurso da POO, declaramos os métodos que quisermos como funções virtuais da classe base. A sintaxe é a seguinte:

virtual <tipo> <nome método> <parâmetros>
Exemplo:
class base { public : virtual void print() { cout << "\nBASE"; }}; class deriv0 : public base { public : void print() { cout <<"\nDERIV0"; } }; class deriv1 : public base { public : void print() { cout <<"\nDERIV1"; } }; class deriv2 : public base { public : void print() { cout <<"\nDERIV2"; } }; void main() { base *p[3]; // matriz de ponteiro para a classe base deriv0 dv0; // objeto da classe deriv0 deriv1 dv1; // objeto da classe deriv1 deriv2 dv2; // objeto da classe deriv2 p[0] = &dv0; p[1] = &dv1; p[2] = &dv2; for (int i = 0; i < 3; i++) p[i]-> print(); } O resultado produzido é : DERIV0 DERIV1 DERIV2 Se não colocarmos a palavra virtual na declaração do método print() da classe base o resultado será: BASE BASE BASE

FUNÇÕES VIRTUAIS PURAS


Criamos funções virtuais puras para o uso de herança de uma classe base que nunca terá um objeto definido. Esta função não possui código. Na declaração do protótipo da função usamos o operador de atribuição seguido de um zero após o seu protótipo. A função serve somente para prover uma interface polimórfica para as classes derivadas. Exemplo :

class base {
        public : virtual void print() = 0; };
class deriv0 : public base { public : void print() { cout <<"\nDERIV0"; } };
class deriv1 : public base { public : void print() { cout <<"\nDERIV1"; } };
class deriv2 : public base { public : void print() { cout <<"\nDERIV2"; } };
void main() { base *p[3]; // matriz de ponteiro para a classe base
deriv0 dv0; // objeto da classe deriv0 deriv1 dv1; // objeto da classe
                deriv1 deriv2 dv2; // objeto da classe deriv2
p[0] = &dv0; p[1] = &dv1; p[2] = &dv2;
for (int i = 0; i < 3; i++) p[i]-> print(); }
O resultado produzido é : DERIV0 DERIV1 DERIV2
A classe base definida acima, não pode ter objetos declarados é chamada de classe abstrata. Contudo, podemos definir um ponteiro para uma classe abstrata para manipular objetos de classes derivadas.

FUNÇÕES AMIGAS


Por default, os membros privados de uma classe somente podem ser acessados por outros membros da mesma classe. Contudo, uma classe pode dar permissão para uma função não membro desta classe acessar os seus membros privados, mas não estará associada a um objeto da classe. Isto é feito com a declaração friend. Uma função amiga pode agir em duas ou mais classes diferentes, fazendo o papel de elo de ligação entre as classes.
Exemplo :
#include <iostream.h> class tempo { private : long segundos; public : tempo(long h, long m, long s) { segundos = h * 3600 + m * 60 +s; } friend char *prntm(tempo); // declaração amiga }; char *prntm(tempo tm) < { char * buff = new char[9]; // new executa uma alocação dinâmica ao invés de ser alocado na pilha int h = tm.segundos / 3600; int resto = tm.segundos % 3600; int m = resto / 60; int s = (resto % 60); buff[0] = h / 10 + '0'; buff[1] = h % 10 + '0'; buff[2] = ':'; buff[3] = m / 10 + '0'; buff[4] = m % 10 + '0'; buff[5] = ':'; buff[6] = s / 10 + '0'; buff[7] = s % 10 + '0'; buff[8] = '\0'; return buff; } void main() { tempo tm(5,8,20); cout << "\n" << prntm(tm); } No exemplo acima, a função prntm() tem acesso ao dado privado da classe tempo. Esta declaração pode ser declarada como pública ou privada, pois, não faz diferença o local onde é declarada.
Além de ser possível declarar funções independentes como amigas, podemos declarar uma classe toda como amiga de outra. Os métodos da classe serão todas amigas da outra classe. A diferença é que estas funções-membro tem também acesso a parte privada ou protegida de sua própria classe.
Exemplo: #include <iostream.h> class tempo { private : long h,m,s; public : tempo (int hh,int mm,int ss) { h = hh; m = mm; s = ss; } friend class data; //data é uma classe amiga }; class data { private : int d,m,a; public : data (int dd,int mm,int aa) { d = dd; m = mm; a = aa;} void prndt (tempo tm) { cout << "\nData: " <<d<<'/'<<m<<'/' <<a; cout << "\nHora: " <<tm.h<< ':'<<tm.m<< ':' <<tm.s; } };
void main() {
tempo tm(12,18,30); tempo tm1 (13,22,10); data dt(18,12,55); dt.prndt(tm); dt.prndt(tm1); }
No exemplo acima, na classe tempo, declaramos toda a classe data como amiga. Então todas as funções-membro de data podem acessar os dados privados de tempo. A palavra chave friend oferece acesso em uma só direção, pois, como no exemplo acima, a classe tempo é amiga da classe data, mas o contrário não é verdadeiro.

SOBRECARGA DE OPERADORES


Sobrecarga de operadores é uma das opções mais poderosas da orientação a objeto. Sobrecarregar um operador significa alterar o domínio de um operador pré-definido de uma linguagem de operação. Por exemplo, o domínio do operador `+' é os números reais. Se desejarmos que o operador `+' ao invés de somar dois números inteiros e passe a somar duas matrizes de dimensões nxn, devemos declarar uma função-membro `operator +' dentro da classe matriz. À partir de agora, cada vez que o operador `+' for executado entre dois objetos da classe matriz ele irá somá-las e atribuir o resultado ´a uma terceira matriz. Sobrecarregar um operador significa redefinir o seu símbolo, de modo que ele se adeque aos tipos abstratos de dados definidos pelo usuário, tais como, estruturas e classes. A implementação de sobrecargas de operadores é definido por meio de funções chamadas operadoras. Estas funções podem ser criadas como membros de classe ou como funções globais.
A sobrecarga de operadores deve respeitar a definição original do operador. Por exemplo, o operador soma necessita de dois argumentos, não podemos modificá-lo para três argumentos. Para realizar a sobrecarga devemos usar os operadores definidos, ou seja, não podemos criar operadores novos. A sobrecarga deve obedecer à precedência original do operador sobrecarregado. Não é possível modificar a precedência dos operadores sobrecarregados.
Os operadores ".", "::" e "?:" não podem ser sobrecarregados. Operadores unários ("++", "--" e "-"), definidos como métodos de classes, não recebem nenhum argumento, enquanto que os operadores binários recebem um único argumento. Podemos sobrecarregar além dos operadores unários e binários, strings. Podemos usar os operadores "=", "+"e "+=" para concatenar e comparar strings.

SOBRECARGA DE OPERADORES UNÁRIOS


A sobrecarga do operador de incremento pré-fixado tem a seguinte sintaxe : void operator ++() { comandos } void operator --() { comandos } A função não recebe nenhum argumento e não retorna nada neste caso. Esta declaração indica ao compilador que este método deve ser executado cada vez que for usado este operador com objetos desta classe. A chamada pode ser duas maneiras : ++p1; ou p1.operator++(); A sobrecarga do operador de incremento pós-fixado tem a seguinte sintaxe : void operator ++(int) { comandos } void operator --(int) { comandos } O parâmetro "int" indica para o compilador que a função sobrecarregada é pós-fixada. Exemplo de um operador sobrecarregado pré-fixado.

#include <iostream.h>
class ponto
{
   private : int x,y; 
   public :
               ponto(int x1=0,int y1=0) // construtor { x = x1; y = y1;}
               void operator ++() // função operadora prefixada { ++x; ++y; }
               void printpt() const // imprime ponto { cout << "("
                        << x << "," << y << ")"; }
}; 
void main() 
{ 
    ponto p1, p2(2,3), p3; // declara e inicializa 
    cout << "\n p1 = "; 
    p1.printpt(); 
    cout << "\n p2 = ";
    p2.printpt(); ++p1; //incrementa p1
    ++p2; // incrementa p2 
    cout << "\n ++p1 = ";
    p1.printpt(); 
    cout << "\n ++p2 = "; 
    p2.printpt(); 
    p3 = p1;                
    cout << "\n p3 = "; 
     p3.printpt(); 
}
Resultado :
p1 = (0,0) 
p2 = (2,3) 
++p1 = (1,1) 
++p2 = (3,4) 
p3 = (1,1)

SOBRECARGA DE OPERADORES BINÁRIOS


Quando operadores binários são sobrecarregados, a função operadora terá um argumento. A função operadora, quando declarada como método de uma classe sempre precisa de um argumento a menos que o número de operandos daquele operador. Exemplo:

#include <iostream.h>
#include <iomanip.h>
class venda
{
   private : 
               int npecas; 
               float preco;
   public : 
               venda() {} 
               venda(int np, float p) // construtor com argumentos { npecas= np; preco = p; } 
               void getvenda() 
               { 
                 cout << "Insira Numero de Pecas: ";
                 cin >> npecas;
                 cout << "Insira Preco : "; 
                 cin >> preco; 
               }
               venda operator + (venda v) const; // funçãooperador 
               void printvenda() const; 
}; 
venda venda::operator + (venda v) const // soma duas vendas 
{
   int pec = npecas + v.npecas;
   float pre = preco + v.preco; 
   return venda(pec,pre); 
}
void venda::printvenda() const 
{
   cout << setiosflags(ios::fixed) // nao notaçãocientifica
            << setiosflags(ios::showpoint) // ponto   decimal
            <<setprecision(2) // duas casas decimais
            << setw(10) << npecas;
                    // tamanho do campo 10
   cout << setw(10) << preco << "\n"; 
}
void main()
{
   venda A(58,12734.53),B,C(30,6000.3),T,Total;
   B.getvenda(); 
   T = A + B; 
   Total = A + B + C; //somas múltiplas
   cout << "Venda A ........"; 
   A.printvenda(); 
   cout << "Venda B ........"; 
   B.printvenda(); 
   cout << "Venda:A + B ....";
   T.printvenda();
   cout << "Totais:A + B + C"; 
   Total.printvenda(); 
   return;
}
Resultado:
Insira No.Peças: 45 
Insira Preço: 10987.85
Venda: A.... 58 12734.53 
Venda: B.... 45 10987.85
Venda A + B: ..... 103 23722.38
Totais A + B + C: 133 29722.68

BIBLIOGRAFIA


[HEA94] HEADINGTON, M. RILEY, D. Data Abstraction and Structures Using C++, D. C. Heath and Company, Toronto, 1994.
[MIZ94a] MIZRAHI, V. Treinamento em Linguagem C++, Módulo 1, Makron Books, SP, 1994.
[MIZ94b] MIZRAHI, V. Treinamento em Linguagem C++, Módulo 2, Makron Books, SP, 1994.


Contents