Linguagem de
Programação II
Carlos Oberdan Rolim
Ciência da Computação
Sistemas de Informação
Classes
Parte II
Funções, métodos e classes friends
Inconveniente gerado pelo uso de private
C++ proporciona uma forma de contorno através de friends que
podem ser funções, classes e métodos
Funções friends
Função friend é uma função nãomembro (não pertence a
uma classe) que permite acesso aos membros da seção
private de uma classe
Quando uma função torna-se friend ela terá os mesmos
privilégios de acesso que um método da classe tem
As funções friend são um pouco diferentes de métodos
Um método é chamado por um objeto específico
Uma função friend por não ser membro de classes, não pode ser
chamada por um objeto. Ao contrário, deverá receber um objeto como
argumento, sobre o qual atuará
#include <iostream>
#include <cstring>
#include <conio.h>
using namespace std;
void exibe (marido h1, esposa h2){
cout << “Nome” << h1.nome1;
cout << “Salario” << h1.salario;
cout << “Nome” << h2.nome2;
cout << “Salario” << h2.salario2;
class esposa; // declaracao antecipada
class marido {
public:
marido(char *, float);
~marido();
friend void exibe(marido, esposa);
private:
char nome1[10];
float salario1;
};
class esposa {
public:
esposa(char *, float);
~esposa();
friend void exibe(marido, esposa);
private:
char nome2[10];
}
int main(){
marido homem(“joao”,2000,00);
esposa mulher(“Maria”, 3000,00);
exibe(homem, mulher);
getch();
return 0;
}
Informações adicionais
Declaração antecipada (forward declaration) diz ao compilador que a
classe está definida mais a frente. É necessária por causa do protótipo
friend void exibe(marido, esposa) que faz referência a classe esposa
que ainda não existe
Como a função recebe um objeto como argumento o protótipo de
função foi declarada como friend exibe(homem, mulher);
(lembrando que no protótipo não preciso informar nome após o tipo)
O cabeçalho de definição da função friend, ao contrário do protótipo,
não possui a palavra friend
Como não pertence a classe não possui o operador de resolução de
escopo ::
A passagem de argumentos pode ser feita por valor, por referência ou
por endereço.
(Lembrando: a passagem de argumentos a uma função friend pode ser
feita por endereço e por referência são mais rápidas e ocupam menos
espaço em memória que por valor)
Passagem por endereço utiliza ponteiros e implica no uso do
operador ->
cout << “Nome” << h1->nome1;
Classes friend
É uma classe cujos métodos podem acessar os membros
das seções private e protected de outra classe.
Quando uma classe é chamada como friend todos os seus
métodos são entendidos como friends
Mas é possível indicar quais métodos de uma classe serão
amigos de uma outra classe
Para indicar que uma classe é amiga de outra escreve-se a
expressão friend class antes do nome da classe amiga, na
declaração da primeira classe
class carro {
public:
carro(char *, int, char *);
void exibe();
friend class fcarro;
private:
char marca [12];
char modelo [7];
int anofab;
// Método da classe amiga fcarro
void altera( carro & c){
strcpy(c.marca, “Ford”);
strcpy(c.modelo, “Focus”);
c.anofab = 2008;
}
int main(){
};
class fcarro{
public:
void altera(carro &);
};
carro :: carro(char * m1, int a, char * m2){
strcpy(marca, m);
strcpy(modelo, m2);
anofab = a;
}
... Implementação do exibe ...
carro carro1(“GM”,2000,”Corsa”);
fcarro fcarro1;
// Passagem do argumento por
//por referencia pois altera as
// variaveis-membro da classe carro
fcarro1.altera(carro1);
getch();
return 0;
}
Métodos friend
É uma classe cujos métodos podem acessar os membros
das seções private e protected de outra classe. Quando uma
classe é chamada como friend todos os seus métodos são
entendidos como friends
Há situações em que nem todos os métodos precisam ser
friends, assim,seleciona-se os métodos da classe friend que
irão acessar as seções private e protected da classe
original:os métodos friends
Para declarar um método friend, declare o seu protótipo na
classe original, iniciando-se pela palavra friend
class fcarro; // declaracao antecipada
class carro {
public:
carro(char *, int, char *);
void exibe();
friend void fcarro::altera(carro &);
private:
char marca [12];
char modelo [7];
int anofab;
// Método da classe amiga fcarro
void altera( carro & c){
strcpy(c.marca, “Ford”);
strcpy(c.modelo, “Focus”);
c.anofab = 2008;
}
int main(){
};
carro carro1(“GM”,2000,”Corsa”);
class fcarro{
public:
void altera(carro &);
};
carro :: carro(char * m1, int a, char * m2){
strcpy(marca, m);
strcpy(modelo, m2);
anofab = a;
}
... Implementação do exibe ...
fcarro fcarro1;
// Passagem do argumento por
//por referencia pois altera as
// variaveis-membro da classe carro
fcarro1.altera(carro1);
getch();
return 0;
}
Classes friend recíprocas
Quando uma classe torna-se friend de outra e vice-versa.
Métodos da classeA torna-se friend da classeB, e esta por
sua vez torna-se friend da classeA
class carro {
public:
friend class fcarro;
carro(char *, int, char *);
void exibe_fcarro(fcarro &);
private:
char marca [12];
char modelo [7];
int anofab;
};
class fcarro{
public:
friend class carro;
fcarro(float,char);
void altera(carro &);
};
int main(){
carro carro1(“GM”,2000,”Corsa”);
fcarro fcarro1(1100., ‘G’);
// Passagem do argumento por
//por referencia pois altera as
// variaveis-membro da classe carro
fcarro1.altera(carro1);
carro1.exibe_fcarro(carro1);
getch();
return 0;
}
... Implementação dos métodos das classes ...
Sobrecarga de operadores
A sobrecarga de operadores é uma forma de polimorfismo
de C++ que permite alterar o significado de seus operadores,
cuja idéia é transformar expressões complexas em
expressões mais claras e intuitivas.
Por exemplo uma expressão
total.soma(p1,p2);
pode ser escrita como
total = p1 + p2;
C++ possui naturalmente vários operadores sobrecarregados
Compilador com base na quantidade e nos tipos de
operandos envolvidos decidirá qual ação executar
Sobrecarga dos tipos básicos também é estentida aos tipos
definidos pelos usuários
Sobrecarga de operadores
Como sobrecarga de operadores é utilizada com tipos
definidos por usuários e como uma classe é um tipo definido
pelo usuário, logo é definido por classe
Quando um operador é sobrecarregado em uma classe, o
seu significado muda apenas para ela, o restante do
programa utilizará o operador com seu significado original
A sobrecarga de operadores utiliza um formato especial de
função chamado função operator
operator operador ([argumentos])
operador  caractere correspondente ao operador a ser
sobrecarregado
argumentos  argumentos a serem passados à função,
separador por virgula
class texto{
public:
texto(char *);
void exibe(int);
void operator –(int);
private:
static const int comp = 25;
char string1[comp];
str_aux[k] = ‘\o’ ;
strcpy(string1,atr_aux);
}
texto :: texto(char :* string2){
strcpy(string1, string2);
}
};
void texto:: exibe(int flag){
if(flag == 1)
cout << “String original: ” << string1;
else
cout << “Substring: ” << string1;
}
void texto :: operator –(int qtd){
int k = 0;
char str_aux[comp];
while(k < qtd){
str_aux[k] = string1[k]
k++;
}
int main(){
texto texto1(“Sobrecarga de operad.”);
texto1.exibe();
texto1 – 5;
texto1.exibe(2);
return 0;
}
Saída:
String original: Sobrecarga de operad
Substring: Sobre
Critérios para sobrecarga de operadores
A maioria dos operadores pode ser sobrecarregado da
mesma maneira. Os operadores com algumas exceções,
não precisam ser necessariamente métodos, porém pelo
menos um dos operados precisa ser um tipo definido pelo
programador
O operador a ser sobrecarregado deve ser um operador
válido C++. Por exemplo, o operador $ não pode ser
sobrecarregado porque não é um operador válido
O operador a se sobrecarregado deve ter pelo menos um
operando que seja um tipo definido pelo programador. Isso
elimina a possibilidade do programador sobrecarregar
operadores que atuam sobre os tipos predefinidos. Assim, o
operador + não pode ser redefinido de forma a subtrair
valores em vez de adicioná-los
Critérios para sobrecarga de operadores
Um operador não pode ser utilizado de forma a violar as
regras originais de sintaxe. Por exemplo, o operador / não
pode ser sobrecarregado para utilizar apenas um operando
A precedência dos operadores não pode ser alterada
Operadores que não podem ser sobrecarregados:
:: . const_cast dynamic_cast reinterpreted_cast
static_cast typeid sizeof . * ?:
Operadores que podem ser sobrecarregados apenas
utilizando-se metodos:
= ( ) [ ] ->
Operadores que não podem se sobrecarregados utilizandose métodos e funções não-membro
+ - * / % ^& | ~ ! = < > += -= *= /= %= ^= &= |=
<< >> >>= <<= == != <= >= && || ++ -- , ->* ->
() [] new delete new[ ] delete[ ]
Passagem de objetos como argumentos
Uma função não precisa ser um método ou função friend
para utilizar um objeto como argumento
Somente se uma função precisa acessar os membros
privados ela terá que ser um método ou função friend
Pode-se passar o objeto por valor, referência e endereço.
Lembrando: Se for passado por endereço utiliza ponteiro e então devese utilizar -> para acessar variáveis e métodos
A passagem por referência pode ser mais conveniente que a
passagem por endereço, pois mascara a utilização de
ponteiros
class Carro{
string marca, modelo;
public:
Carro(){}
Carro(string, string);
void exibe();
void altera(Carro);
int main() {
Carro carro("Fiat", "uno");
carro.exibe();
carro.altera(carro);
};
Carro :: Carro(string marca, string modelo){
this->marca = marca;
this->modelo = modelo;
}
return 0;
void Carro :: exibe(){
cout << "Marca:" << marca << "\n“;
cout << "Modelo:" << modelo << "\n“;
}
Saída
void Carro :: altera( Carro c){
c.marca = "Nova marca“;
c.modelo = "Novo modelo“;
c.exibe();
Modelo:uno
}
}
Note que o objeto
alterado foi o “c” e não
o “carro”. Para alterar
“carro” deveria ser
passado por referencia
Marca:Fiat
Marca:Fiat
Modelo:uno
Marca:Nova marca
Modelo:Novo modelo
class Carro{
string marca, modelo;
int main() {
Carro carro("Fiat", "uno");
public:
carro.exibe();
Carro(){}
carro.altera(carro);
Carro(string, string);
void exibe(Carro);
return 0;
}
};
Carro :: Carro(string marca, string modelo){
Saída
this->marca = marca;
this->modelo = modelo;
Note que o objeto
alterado foi o “c” e não
o “carro”. Para alterar
“carro” deveria ser
passado por referencia
Marca:Fiat
Modelo:uno
}
Marca:Fiat
Modelo:uno
void Carro :: exibe(Carro c){
cout << "Marca:" << c.marca << "\n";
cout << "Modelo:" << c.modelo << "\n";
Marca:Nova marca
Modelo:Novo modelo
Retorno de objetos
Da mesma forma que uma função comum um método
também pode retornar um valor que pode ser um objeto
Retorno é feito com return normalmente
class Numero{
int a, b;
public:
Numero(){}
Numero(int, int);
Numero inverte();
void mostra();
void Numero :: mostra(){
cout << "A: " << a << "\n“;
cout << "B: " << b << "\n";
}
int main() {
};
Numero n(1,2), n2;
Numero :: Numero(int a, int b){
this->a = a;
this->b = b;
}
n.mostra();
n2 = n.inverte();
n2.mostra();
Numero Numero :: inverte(){
Numero n;
n.a = b;
n.b = a;
return n;
}
return 0;
}
Saída:
A: 1
B: 2
A: 2
B:1
Membros static
Uma variável-membro de classe de memória static é uma
variável única, criada para uma dada classe, que fica
disponível a todos os objetos que vierem a ser criados.
É utilizada para compartilhar informações entre objetos de
uma classe
Existe independente da criação de objetos e permanece na
memória durante a execução do programa podendo ser
acessada sem a existência de objetos
Quando um objeto é criado ele passa a ter as variáveismembro da classe que o originou.
Uma variável static não é armazenada nos objetos da
classe, mas seu conteúdo fica disponível a todos os objetos
que venham a ser criados
A sua utilização implica economia de memória e tempo de
processamento
class carro {
public:
carro(char *,char *);
private:
char modelo [7];
char marca[10]
static int cont;
int main(){
carro carro1(“GM”,”Corsa”);
carro carro2(“VW”,”Fusca”);
getch();
};
int carro :: cont = 0;
return 0;
}
carro :: carro(char * marc, char * mod){
Saida:
strcpy(marca, marc);
strcpy(modelo, mod);
cont++;
cout << “Criado objeto numero” << cont;
}
carro :: ~carro() {
cout << “Destruicao do objeto “ << modelo;
}
Criado objeto numero 1
Criado objeto numero 2
Destruicao do objeto 2
Destruicao do objeto 1
Métodos static
Um método da classe de memória static não precisa ser
chamado por um objeto pois não possui um ponteiro this
associado, podendo existir independente da existência de
objetos
class carro {
public:
static void exibe();
private:
char modelo [7];
char marca[10]
static int anofab;
int main(){
// Chama o metodo static exibe() sem
// a existencia de objetos da classe carro
//Acessa a variavel compartilhada anofab
carro :: exibe();
};
getch();
int carro :: anofab = 2000;
carro :: exibe(){
return 0;
}
cout << “Ano fabricacao ” << anofab;
Saida:
}
Ano fabricacao 2000
Classes e alocação dinâmica de memória
A alocação de memória é aquela que ocorre durante a
execução de um programa (não em tempo de compilação)
e é efetuada pelo operadores new e new[ ]
new  utilizado para alocação dinâmica de um valor
Sintaxe: tipo * ponteiro = new tipo;
Exemplo: int * ptr_int = new int; // alocacao de um inteiro
struct st_produto * ptr= new struct st_produto;
ptr -> nome = “joao”; // acesso ao elemento nome
Usar o operador delete para desalocar
delete ptr;
Classes e alocação dinâmica de memória
new[ ]  utilizado para alocação dinâmica de um array
Sintaxe:
tipo * ponteiro = new tipo [ quantidade ];
Exemplo:
cin >> qtd;
int * ptr = new int[qtd]; // alocacao de um vetor
ptr[0] = 1;
ptr[1] = 2;
Usar o operador delete[ ] para desalocar
delete ptr[ ];
class xstring{
public:
void le_nome();
void exibe();
~xtring();
private:
char * texto;
};
void xstring :: exibe(){
cout << “Ola “ << texto;
}
void xstring :: le_nome() {
texto = new char[30];
cin.get(texto,30);
}
void xstring :: ~xstring(){
cout << “Obeto “ << texto << “destruido”;
delete [ ] texto;
}
int main(){
xtring nome;
nome.le_nome();
nome.exibe();
return 0;
}
Classes e alocação dinâmica de memória
O detalhe mais importante do programa: quando o objeto
nome é destruido, o ponteiro texto também o é, mas a
memória apontada pelo ponteiro texto continua alocada.
Daí a necessidade de utilizar o destrutor, e nesse, o
operador delete [ ] para liberar a referida memória. Observe
que o programa funciona sem o operador delete [ ], mas
omiti-lo não é uma boa prática de programação
Download

Carro