Você está na página 1de 80

Fundamentos de Programao em C++

Abstrao de Dados em C++


Uso de classes

Classes permitem criar TAD em C++ As classes possuem regies de acesso


private, protected e public

Em C++ classes e estruturas so bastante semelhantes


Na classe o nvel de visibilidade default private e na estrutura public

Abstrao de Dados em C++


Uso de classes

Classes possuem membros


Funes membros (Mtodos) Dados membros (Variveis)

Membros podem ser estticos ou no estticos


Estticos
Mtodos ou variveis de classe

No Estticos
Mtodos ou variveis de instncia

Exemplo de Classe em C++


Classe Pilha
class Pilha { public: Pilha(int max = 10); ~Pilha(); void push(int valor); int pop(); private: int MAX_PILHA; int *dados; int tamanho; };

Construtores

Funes membro especiais cujo nome o prprio nome da classe Responsveis pela inicializao dos novos objetos criados No possuem valores de retorno
No pode ser mtodo do tipo const No podem ser do tipo static

Podem ser sobrecarregados, criando-se vrios construtores


Parmetros podem ter valores default

Construtor da Classe Pilha


Formato 1: Atribuio no corpo
Pilha::Pilha(int max) { MAX_PILHA = max; tamanho = 0; dados = new int[MAX_PILHA]; }

Formato 2: Lista de inicializao


Pilha::Pilha(int max) :MAX_PILHA(max), tamanho(0){ dados = new int[MAX_PILHA]; }

Construtores Especiais
Construtor Padro

Construtor que no recebe nenhum parmetro denominado construtor default Caso no se programe nenhum construtor, o compilador gera um construtor default Caso se programe algum construtor, o compilador deixa de fornecer o construtor default

Construtores Especiais
Construtor de Cpia

Seja o exemplo
Pilha p1(100); p1.push(10); p1.push(20); Pilha p2 = p1; p1.pop(); p1.push(30); cout << "Topo de p2" << p2.pop();

Qual ser a sada deste programa?

Construtores Especiais
Construtor de Cpia

O problema que o construtor de cpia gerado automaticamente faz cpia superficial (bitwise)

Cdigo do construtor de cpia Pilha::Pilha(const Pilha &pOriginal): MAX_PILHA(pOriginal.MAX_PILHA), tamanho(pOriginal.tamanho) { dados = new int[MAX_PILHA]; for (int i = 0; i < tamanho; ++i) dados[i] = pOriginal.dados[i]; }

Destrutores

Funo membro especial cujo nome o nome da classe precedido por ~ Responsveis pela liberao de memria dos objetos alocados No possuem valores de retorno No pode ser mtodo do tipo const No podem ser do tipo static No podem ser sobrecarregados, no recebem parmetros Um destrutor default fornecido pelo compilador

Destrutor da Classe Pilha


Responsvel por liberar a memria alocada dinamicamente para dados
Pilha::~Pilha() { delete []dados; }

Operador de atribuio Seja o exemplo


Pilha p1(100), p2(100); p1.push(10); p1.push(20); p2 = p1; p1.pop(); p1.push(30); cout << Topo de p2 << p2.pop();

Problema

No definido operador =

Operador de atribuio
Implementao
Pilha & Pilha::operator=(const Pilha &pOriginal) { if (this != &pOriginal) { delete [] dados; dados = new int[pOriginal.MAX_PILHA]; tamanho = pOriginal.tamanho; for (int i = 0; i < tamanho; ++i) dados[i] = pOriginal.dados[i]; } return *this; }

Herana de Classes

Herana de Classes
Tipos de Herana

Herana Simples Subclasse herda de uma nica superclasse Herana Mltipla Subclasse herda caractersticas de duas ou mais superclasses

Sintaxe Geral
class SubClasse: [modificador] SuperClasse1, [modificador] SuperClasse2, ... [modificador] SuperClassen { ... };

Herana Simples
Hierarquia de classes para Bovinos
Animal
class Animal { public: Animal(int q): quant(q) {}; ~Animal() {}; Modificador private: int quant; de Acesso }; class Bovino: public Animal { public: Bovino(int q, char *r) : Animal(q), raca(r) {}; ~Bovino() {}; private: char raca[31]; };

Bovino

Leiteiro

Modificadores de Acesso da Herana


Objetivo

Determinar como os nveis de visibilidade public e protected sero vistos pelas subclasses
Modificador de Acesso public public public private private private Acesso resultante public protected No acessvel private private No acessvel

Modificador default private


Tipo de Acesso public protected private public protected private

Polimorfismo
Poligono area();

Triangulo area();

Retangulo area();

Hexagono area();

Polimorfismo em C++
Mtodos Virtuais
class Poligono { virtual float area() {...} }; class Retangulo: public Poligono { float area() {...} }; class Triangulo : public Poligono { float area() {...} };

Polimorfismo em C++
Referncia para o tipo Poligono pode assumir a forma de Poligono, Triangulo, Retangulo e Hexagono
main() { Poligono *p; P = new Poligono(); p->area(); P = new Triangulo(); P->area(); }

Exemplo de uso de Polimorfismo


rea total com polimorfismo
double areaTotal = 0; for (int i = 0; i < MAXPOLIG; ++i) { areaTotal += poligono[i].area(); }

Facilidade de expanso

Caso se deseje trabalhar com uma nova classe chamada Quadrado, este trecho de cdigo no ser alterado em nada.

Classes Abstratas em C++


Mtodos Virtuais Puros
class Poligono { virtual float area() = 0; }; class Retangulo: public Poligono { float area() {...} }; class Triangulo : public Poligono { float area() {...} };

Uso de classes abstratas


Classe Poligono no permite ser instanciada Pode-se declarar apontadores para a classe Poligono
main() { Poligono objPol; Poligono *p; p = new Poligono(); p = new Triangulo();

// Erro // OK // Erro // OK

Herana Mltipla
Veiculo

Terrestre

Aquatico

Anfibio

Exemplo de Herana Mltipla


class Veiculo { public: Veiculo(int na): assentos(na) {} int getAssentos() { return assentos; } protected: int assentos; }; class Terrestre : public Veiculo { public: Terrestre(): Veiculo(5) {} void mover() { cout << "Anda na estrada\n"; } };

Exemplo de Herana Mltipla


class Aquatico : public Veiculo { public: Aquatico(): Veiculo(10) {} void mover() { cout << "Anda na gua\n"; } }; class Anfibio: public Terrestre, public Aquatico { public: Anfibio(char local) : local(local) {} private: char local; };

Problemas da Herana mltipla


Conflitos de nomes

O mesmo nome de mtodo ou varivel de instncia existe em mais de uma das superclasses. Qual deles herdar?

Terrestre mover() Anfibio

Aquatico mover()

Resolvendo Conflitos de Nomes


class Anfibio: public Terrestre, public Aquatico { public: Anfibio(char local) : local(local) {} void mover() { if (local == 'A') Aquatico::mover(); else Terrestre::mover(); } private: char local; };

Problemas da Herana mltipla


Duplicao de classes herdadas Veiculo
Terrestre Veiculo

Veiculo
Aquatico

Anfibio

Resolvendo Duplicao de Classes


class Terrestre : public virtual Veiculo { public: Terrestre(): Veiculo(5) {} void mover() { cout << "Anda na estrada\n"; } }; class Aquatico : virtual public Veiculo { public: Aquatico(): Veiculo(10) {} void mover() { cout << "Anda na gua\n"; } };

Resolvendo Duplicao de Classes


class Anfibio: public Terrestre, public Aquatico { public: Anfibio(char local) : Veiculo(50), local(local) {} void mover() { if (local == 'A') Aquatico::mover(); else Terrestre::mover(); } private: char local; };

Problemas da Herana mltipla


Ambiguidade de superclasses

Ao se usar polimorfismo paramtrico pode ser impossvel definir qual tipo de mtodo ser invocado com base na classe que foi criada atravs de herana mltipla void f(Aquatico x) { x.mover(); } void f(Terrestre x) { x.mover(); } main() { Anfibio sapo('T'); f(sapo); // Qual f() chamar? }

Resolvendo Ambiguidades de Superclasses


void f(Anfibio x) { x.mover(); } ... main() { Anfibio sapo('T'); f(sapo); return 0;

Classes e Funes Amigas

Classes Amigas
Seja a classe Empregado
E m p re g a d o
n o m e : stri n g sa l a ri o : d o u b l e g e tS a l a ri o () se tS a l a ri o () g e tNo m e () se tNo m e ( )

Para pensar

Todos as classes podem alterar o salrio de um Empregado No h um mecanismo para controlar as classes que podem acessar um mtodo pblico Aspecto indesejado para a classe empregado

Classes Amigas
Uso de uma classe amiga
E m pregado
n o m e : s trin g

DRH
re vis a S a la r io s ()

< < friend> >

s a la rio : d o u b le g e tS a la rio ( ) g e tN o m e () s e tN o m e ()

Classe DRH acessa todos os dados internos de Empregado

Classes Amigas
class DRH; // Implementada mais a frente class Empregado { public: double getSalario(); string getNome(); void setNome(string umNome); private: string nome; double salario; friend class DRH; }

Classes Amigas
class DRH { public: void revisaSalarios(Empregado &emp);

} DRH::revisaSalarios(Empregado &emp) { // Define reajuste emp.salario += reajuste; }

Classes Amigas
Problemas dessa abordagem

A classe DRH agora acessa todos os membros de Empregado, sejam eles pblicos, protegidos ou privados No h como garantir para DRH o acesso apenas ao membro salario Caso apenas o mtodo revisasalarios necessite acessar o membro salario, pode-se usar uma abordagem com mtodo amigo

Mtodos Amigos
Uso de um mtodo amigo
Empregado DRH
revisaSalarios() nome : string salario : double

<<friend>>

getSalario() getNome() setNome()

Apenas o mtodo revisaSalarios da Classe DRH acessa todos os dados internos de Empregado

Mtodos Amigos
class DRH { public: void revisaSalarios(Empregado &emp); } class Empregado { public: double getSalario(); string getNome(); void setNome(string umNome); private: string nome; double salario; }

friend DRH::revisaSalarios(Empregado &emp);

Funes Amigas
Uso de uma funo amiga
Empregado
nome : string salario : double revisaSalarios()

<<friend>>

getSalario() getNome() setNome()

A funo revisaSalarios acessar todos os dados de Empregado

Funes Amigas
class Empregado { public: double getSalario(); string getNome(); void setNome(string umNome); private: string nome; double salario; }

friend revisaSalarios(Empregado &emp);

revisaSalarios(Empregado &emp) { // Define reajuste emp.salario += reajuste; }

Uso de classes e funes friend


Otimizao da interao entre classes fortemente acopladas

Caso se tenham classes que embora no se relacionem via herana, esto fortemente acopladas e a performance est sendo afetada pela comunicao entre as classes, pode-se definir uma classe como amiga da outra para minimizar o overhead das chamadas de mtodo entre as classes preciso registrar que esta abordagem viola o princpio do encapsulamento e s deve ser usada de forma controlada.

Uso de classes e funes friend


class NoPilha { public: void setValor(int valor); int getValor(); void setProx(NoPilha * const p); NoPilha *getProx(); private: int valor; NoPilha *prox; }; class Pilha { public: Pilha(); void push(int valor); int pop(); private: NoPilha *topo; }

Uso de classes e funes friend


class NoPilha { private: int valor; NoPilha *prox; friend class Pilha; }; class Pilha { private: NoPilha *topo; public: Pilha(); void push(int valor); int pop(); }

Uso de classes e funes friend


Eliminando problemas de sintaxe

Em geral, quando se faz sobrecarga de operadores preciso trabalhar com funes friend para garantir a sintaxe habitual do operador Veremos esse tpico em detalhes no estudo de sobrecarga de operadores

Funes que se comunicam com mais de uma classe

Operaes realizadas entre 2 classes distintas

Uso de classes e funes friend


Operao de multiplicao entre um vetor e uma matriz
class Vetor { public: friend Vetor multiplica( const Vetor &v, const Matriz &m); }; class Matriz { public: friend Vetor multiplica( const Vetor &v, const Matriz &m); }; Vetor multiplica( const Vetor &v, const Matriz &m) { // Implementa multiplicao }

Problema 05
Implemente as classes Vetor e Matriz onde:

Vetor possui os mtodos getValue(x) e setValue(x) para acessar e setar valores Matriz possui os mtodos getValue(x, y) e setValue(x,y) nos mesmos moldes Os dados so privados

Problema 06
Implemente a funo friend de multiplicao de matriz por vetor

Polimorfismo Paramtrico e Sobrecarga de Operadores

Sobrecarga de funes
Pode-se sobrecarregar uma funo com declaraes mltiplas do mesmo nome de funo no mesmo escopo. As declaraes diferem no nmero e no tipo dos argumentos recebidos.
void imprima(int i) { cout << "Um int " << i << endl; } void imprima(double d) { cout << "Um double " << d << endl; }

Sobrecarga de funes
As funes sobrecarregadas podem ser funes membro (ou mtodos) de uma classe
class Documento { public: void imprima(char *titulo); void imprime(char *titulo, int copias); void imprime(int copias); }

O que sobrecarga de operadores


Seja uma nova classe RangeInt

Define um tipo inteiro que guarda valores numa determinada faixa Contruo desejvel para um cliente da classe RangeInt seria
RangeInt x, y, z; x = 100; y = 150; z = x + y;

Caso no se tenha sobrecarga de operadores pode-se trabalhar com mtodos para definir as operaes

O que sobrecarga de operadores

Usando mtodo para adicionar


RangeInt x, y, z; x = 100; y = 150; z = x.add(y);

Isso no fica uma construo natural


RangeInt quase um int, trat-lo de forma diferente limitar o seu uso Como fazer para adicionar a um int normal o valor de y?

Sobrecarga de operadores usada

Sobrecarregando operadores
Formas de Sobrecarga

Operadores como mtodos da classe Operadores como funes friend da classe Operadores como funes gerais

Sintaxe geral
<tipo> operator <smbolo>(<parmetros>);

Observaes

Dependendo do tipo de implementao da sobrecarga (mtodo ou funo) e do tipo do operador (unrio ou binrio) o total de parmetros ser alterado

Sobrecarregando operadores
Sobrecarga do operador + de RangeInt
class RangeInt { public: ... RangeInt(int val = 0); RangeInt operator+(RangeInt &opDireita) { if ( valor + opDireita.valor > high || valor + opDireita.valor < low) { // Gera exceo } return RangeInt(valor+opDireita.valor); } ... };

Sobrecarregando operadores
Contruo vlida
RangeInt x, y, z; x = 100; y = 150; z = x+y; z = x.operator+(y)

E o que dizer desta?


RangeInt x, y, z; y = 150; z = 100+y; z = 100.operator+(y)

100 do tipo base int e no aceita um RangeInt como parmetro de +

Sobrecarregando operadores
Sobrecarga com funo friend
class RangeInt { ... friend RangeInt operator+(const RangeInt &, const RangeInt &) }; inline RangeInt operator+(const RangeInt &esq, const RangeInt &dir) { RangeInt novo; if (esq.valor + dir.valor > esq.high || esq.valor + dir.valor < esq.low) { // Gera exceo } else { novo.valor = esq.valor + dir.valor; } return novo; }

Sobrecarga de Operadores
class MyInt { public: MyInt(int x) : value(x) {} int getValue() const { return value;} MyInt operator+(const MyInt &op) { return MyInt(value + op.value); } MyInt operator+(int op) { return MyInt(op + value); } friend ostream &operator<<(ostream& o, MyInt& p) { o << p.getValue(); return o; } private: int value; };

Restries na sobrecarga de operadores


No se pode sobrecarregar os smbolos de preprocessamento # e ##

Smbolos tratados diretamente pelo prprocessador

Os operadores de C++ a seguir no podem ser sobrecarregados: . .* :: ?: No se pode mudar a precedncia, o nmero de operandos ou agrupamento dos operadores padro de C++

Restries na sobrecarga de operadores


Deve-se declarar a sobrecarga dos operadores =, [], () e -> como membro no esttico, para assegurar que eles recebem lvalues como o primeiro operando Para todos os operadores exceto o operador =, o operador herdado pelas subclasses Operador sobrecarregado (exceto o operador de chamada de funo) no pode ter argumentos default

Operadores Incremento e Decremento


Os operadores de incremento (++) e decremento (--) oferecem um dilema

Como diferenciar as verses pr e ps incremento (decremento) se o nmero de argumentos no varia? ++x x.operator++(); x++ x.operator++(); ???? Ps-incremento (decremento) recebe um parmetro fictcio do tipo int ++x x.operator++(); x++ x.operator++(int nao_usado);

Regras para sobrecarga de operadores


Qualquer operador que no requer um lvalue e comutativo (+, -, etc.) melhor implementado como uma funo no membro (possivelmente um friend)

Permite o compilador fazer converses de tipos incorretos no primeiro argumento Garante a sintaxe correta (usual) do operador Permite usar classes j definidas (ou tipos base) como primeiro operando do operador

Qualquer operador que requer um lvalue melhor implementado como uma funo membro

Retornando valores de operadores


Uso de referncia quando operador do tipo lvalue

Permite operaes em cascata: a = b = c; cout << "x = " << x << endl;

Uso de retorno por valor quando o operador criar um novo objeto

Operador binrio + cria um novo objeto a = b + c; Para evitar que o resultado seja usado como um lvalue retorna-se uma constante b + c = a; // Invlido

Converses de Tipos
C++ realiza converses automticas de tipos Usando construtor de converso de tipo class A { class B { public: public: A() {} B(const A &objA) {} }; }; void f(B b) {} main() { A a; f(a); }

Converses de Tipos
Usando operador de converso class C { int i; public: C(int ii) { i = ii; } }; class D { int x; public: D(int xx) { x = xx; } operator C() const { return C(x); } };

Converses de Tipos
Inibindo converses automticas class A { public: A() {} }; class B { public: explicit B(const A &objA) {} }

Classes e Funes Template

Classes Template
Implementao na linguagem C++ do conceito de genericidade Conhecidas tambm como classes genricas ou geradores de classes Sintaxe de definio
template <class TipoTemp_1,, class TipoTemp_n> class NomeClasse { // Definio da classe template };

Partes em vermelho so opcionais

Exemplo de Classe Template


template <class T> class Vetor { protected: T *elem; private: int numElem; public: Vetor(int tam); virtual ~Vetor() { delete [] elem; } int size() { return numElem; } T& operator[](int i) { return elem[i]; } };

Exemplo de Classe Template


template <class T> Vetor<T>::Vetor(int tam) { elem = new T[tam]; numElem = tam; } template <class T> ostream& operator<<(ostream &s, Vetor<T> &v) { for (int i = 0; i < v.size(); ++i) s << v[i] << " "; return (s << endl); }

Uso de Classe Template


main() { Vetor<int> vInt(10); Vetor<string> vStr(10); ostringstream ss; for (int i = 0; i < 10; ++i) vInt[i] = 10-i; cout << vInt << endl; for (int i = 0; i < 10; ++i) { ss << 10-i; vStr[i] = ss.str(); ss.str(""); } cout << vStr << endl;

Herana de Classe Template


template <class T> class VOrdenado : public Vetor<T> { public: VOrdenado(int tam): Vetor<T>(tam) {} void ordena(); }; template <class T> void VOrdenado<T>::ordena() { int menor; T aux; for (int i = 0; i < size() - 1; ++i) { menor = i;

Herana de Classe Template


for (int j = i+1; j < size(); ++j) if (elem[j] < elem[menor]) menor = j; if (i != menor) { aux = elem[i]; elem[i] = elem[menor]; elem[menor] = aux; } } }

Uso de VOrdenado
main() { VOrdenado<int> vInt(10); Vordenado<string> vStr(3); for (int i = 0; i < 10; ++i) vInt[i] = 10-i; cout << vInt << endl; vInt.ordena(); cout << vInt << endl; vStr[0] = "Zebra"; vStr[1] = "Ana"; vStr[2] = "Carla"; cout << vStr << endl; vStr.ordena(); cout << vStr << endl; }

Problema com VOrdenado


main() { Vordenado<string> vStr1(3); Vordenado<char *> vStr2(3); vStr1[0] = "Zebra"; vStr1[1] = "Ana"; vStr1[2] = "Carla"; vStr1.ordena(); cout << vStr1 << endl; vStr2[0] = "Zebra"; vStr2[1] = "Ana"; vStr2[2] = "Carla"; vStr2.ordena(); cout << vStr2 << endl;

Soluo: Sobrecarga de ordena()


void VOrdenado<char *>::ordena() { int menor; char* aux; for (int i = 0; i < size()-1; ++i) { menor = i; for (int j = i+1; j < size(); ++j) if (strcmp(elem[j], elem[menor]) < 0) menor = j; if (i != menor) { aux = elem[i]; elem[i] = elem[menor]; elem[menor] = aux; } } }

Iteradores
Funcionam como apontadores

Podem ser incrementados/decrementados Pode-se obter o seu contedo ou campo apontado Iteradores so classes criadas com o objetivo de simular apontadores H um controle maior sobre o mecanismo de funcionamento do iterador So chamados super-apontadores Independncia da classe a ser percorrida pelo iterador

No so simplesmente apontadores

Grande uso

Iterador para a classe Vetor


template <class T> class VetorItr { Vetor<T> &v; T *pos; public: VetorItr(Vetor<T> &v) : v(v) { pos = &v.elem[-1]; } bool operator++() { if (pos != &v.elem[v.numElem-1]) { ++pos; return true; } else return false; } T& operator*() { return *pos;} };

Você também pode gostar