POO, introdução
A programação é orientada não pela decomposição de tarefas mas pela identificação das entidades que constituem o problema e como são modelizadas e manipuladas
os mecanismos:
Encapsulamento;
Herança;
Encapsulamento:
integridade da informação numa única estrutura a informação, e as funções que trabalham essa informação
acesso à informação é muito controlada
Herança:
coisas em comuns entre conceitos
(funcionários, funcionário administrativo, gestor, …)
sub-classes, surgem as estruturas que derivadas ou herdar do “pai”
Polimorfismo:
poli, várias, morfismos, formas
a mesma instrução pode ser usada em diferentes ações com significado análogo
as Classes, têm:
Estruturas
Classes
Construtores
Destrutor
Funções membros inline
Membros variáveis estáticos
Funções membros estáticas
Funções membros constantes
Funções friend
Construtores – lista de inicialização
Construtores – membros constantes não estáticos
Construtores – membro referência
Membros variáveis inicializados na declaração ( C++11)
Construtores que chamam construtores ( C++11)
Membros default e delete ( C++11)
passagens por referencia vs passagem por valor
nas classes deve haver relações explicitas entre a estrutura e as funções surgem as funções membros
. é a notação para aceder aos membros das classes
os membros podem ser:
privados (por defeito se fosse uma struct era ao contrário), em privado, as variáveis públicas, as funções membro por norma (funções: set, imprimir..)
funções:
get, servem para obter valores, para comparar (retornam copias dos valores)
criamos as funções/métodos usando :: (por exemplo: Estrutura::get..)
:: são funções que pertencem à classe, não são globais
funções inline:
o código é expandido no local da chamada
funções pequenas
chamadas muitas vezes
p.e. detetar se um numero é par
declara-se a função com a expressão inline
inline int par(int numero){
…
}
funções overloaded:
têm o mesmo nome no mesmo contexto
distinguem-se pelo número de argumentos
p.e.
data(“11/11/11”);
data(11,11,11);
void data (char * s)
void data(int n1, int n2, int n3)
função destrutor:
funciona automaticamente, quando um objeto é destruído ou perde a validade;
podemos precisar numa classe;
usada quando o objeto é destruído e precisamos de executar uma ação de seguida;
libertar por exemplo um espaço de memória dinâmica
o destrutor não tem parâmetros como o construtores
Os objetos locais não estáticos são destruídos quando a execução do programa sai do bloco onde foram declarados.
Os objetos globais são destruídos quando o programa termina.
Os objetos dinâmicos são destruídos com o operador delete.
e os objetos são destruídos por ordem inversa da construção
funções com argumentos por omissão:
A lista de parâmetros com os valores por omissão deve estar apenas na declaração da função cuidado com os erros de ambiguidade (onde existe mais do que uma hipótese)
membros e funções membros estáticos:
têm que ser criados fora dos construtores
são partilhados por todos os objetos da classe
existe apenas uma única versão
está sempre fora dos objetos
p.e.
um predio e um elevador
o prédio tem andares que são objectos
o elevador é o membro estático, que todos usam
e quem usar o elevador pode deixar lá um aviso/atualização
(é uma especie de global na classe)
também existem funções estáticas
a chamada de uma função estática deve ser sempre com ::, mesmo se o objeto existir
funções
no fim, não altera os membros dos objetos
Funções membros constantes, const :
não podem alterar os membros variáveis do objecto
são funções de consulta
poem-se na declaração e na implementação
se um objecto é const, então todas as funções têm que ser const, mesmo que essa função não altere nada
Apenas uma função membro declarada como constante pode ser invocada por objectos constantes.
p.e.:
const int * p;
ou
int const * p;
const antes do *, o ponteiro é um ponteiro que só serve para consultar o apontado, não altera o apontado, mas pode ser apontando para outro local em memória
const depois do *, o ponteiro é constante, tem um endereço e não pode ter outro, não pode apontar para outro sitio
int * const p = &i;
ponteiro constante para constante, const antes e depois do *
const int * const p = &i;
ou
int const * const p = &i;
aponta para uma localização de memória e não se pode alterar essa localização de memória
e também não pode alterar o apontado
parâmetros do tipo ponteiro para constante:
apenas se passa o endereço
garantia de não se alterar a variável
p.e.:
void g(const Elemento * p) //eficiência e segurança
int main(){
Elemento val;
g(&val);
}
ou
void f(const Elemento & arg) //referencia por constante: eficiência e segurança – c++
Funções friend
é uma função que, não sendo membro da classe, tem acesso aos seus membros privados
cuidado que isto é uma quebra do encapsulamento e da integridade dos dados
só deve ser usada com uma justificação forte!
vectores:
notação:
vector v1 = {…};
ou
vector v1(..);
limpar vectores:
v1.clear()
percorrer vectores:
for (const string &c : canais0) {canais.push_back(c);}
ou usando interadores
for(auto it = canais0.begin; it!= canais0.end(); ++it){
canais.push_back(*it);
}
o iterador trata-se como se fosse um ponteiro
initializer_list:
é uma coleção de vectores constantes de um tipo especificado
p.e.
class Televisao{
public:
Televisao(initializer_list<string>canais0);
void setCanais(initializer_list<string>canais0);
}
para criar um objecto do tipo Televisao:
Televisao tv ={“um”, “dois”}; //tv é um objecto Televisao
Usar initializer_list como argumento:
tv.setCanais({“um”, “dois”});
Criar um objeto anónimo
tv = {“um”, “dois”};
inicialização de vectores com construtores:
class Televisao{
vector canais;
public:
Televisao(string canais0[], int n);
}
em que p.e.:
string canais[] = {“um”, “dois”};
Televisao tv = {canais, 2};
ou
Televisao tv {canais, 2};
dedução de tipo: auto
o compilador determina automaticamente o tipo de uma variável
p.e.:
vector::const_rever_interator pesquisa();
p.e.:
int tabela[10];
for(auto & elemento : tabela)
instrução
o uso da referência &, podemos alterar os elementos da coleção (mais eficiente, não faz cópias)
o não uso da referência &, é uma copia do coleção
ou em alternativa para obter eficiência e segurança
for(const auto & elemento : tabela) //não alteramos nada
o nulltpr, é uma constante que representa um ponteiro nulo
0 e NULL são do tipo int em funções overloaded
as referências:
é um outro nome para uma variável, é como que um ponteiro constante que automaticamente conduz ao objeto apontado
p.e.:
void f(int &n);
int main(){
int i =0;
f(i);
cout << x << endl; //100
}
void f(int &n){
n=100;
}
uma referencia como retorno:
int & f();
int x = 0;//global
int main(){
f() = 100;
cout << x << endl; // 100
}
int & f(){
return x;
}
………..construtores, membros constantes não estáticos:
se numa classe existem membros const é obrigatório inicializar no construtor
class Test
{
const int t;
public:
Test(int t0) : t(t0)
………..construtores, membro referência:
class Test2
{
int & t;
public:
Test2(int &t0) : t(t0)
{
};
int getT() const
{
return t;
}
};
int main()
{
int x = 10;
Test2 t2(x);
cout << t2.getT() << endl;
}
membro default:
construtor = default, damos à classe um comportamento default
respeita a inicialização na zona privada
assim o default disponibiliza
membro delete:
vai tornar indisponível a implementação de construtor por omissão, construtor por cópia, operador atribuição, e destrutor
assim o delete impede/proíbe que exista:
construtor por omissão, construtor por cópia, operador atribuição, e destrutor
………..Variáveis em memória dinâmica:
operador new: requisitar memória, e que invoca o construtor
operador delete: para libertar a memória dinâmica
p.e.:
pVar = new tipo;
delete pVar;
p.e.:
Produto* p = new Produto();
cout << p->getAsString() << endl;
delete p;
posso fazer uma reserva com:
int *v2 = new int() //() garantem que vem 0
delete v2
objectos em memória dinâmica:
uso do new, reserva memória para uma variável do tipo classe, e desencadeia o construtor
uso do delete, activa a execução do destrutor
p.e.:
class Ponto {
int x; // abcissa
int y; // ordenada
public:
Ponto() { cout << “Construindo \n”; x = 0; y = 0; }
~Ponto() { cout << “Destruindo \n”; }
void imprime() { cout << “x=” << x << ” y=” << y << endl; } }; int main(void) { Ponto * p = new Ponto; p->imprime();
delete p;
}
existe uma alternativa a:
Ponto * p = new Ponto;
que pode ser com argumentos
Ponto * p = new Ponto{2,2};
criando por exemplo:
criando por exemplo:
Ponto(int x0, int y0) { cout << “Construindo \n”; x = x0; y = y0; }
………..criar um array dinâmico de variváveis de um tipo:
criar:
Ponto * p = new Ponto[4];
libertar:
delete [] pVar
os operadores:
o ponteiro this:
implicitamente nas funções normal membro, não estáticia, a palavra this representa o objecto que invocou a função
………..operadores overloaded:
p.e. existem dois ou mais objectos de uma determinada classe
podemos querer aplicar os operadores que se usam para os tipos primitivos, como é o caso de:
+
–
*
/
%
=
+=
e vão ter as mesmas regras de prioridade e associatividade
expandidmos assim para operandos das classes
usamos assim o operator
p.e. operator+
………..operadores binários:
p.e.: se o operador estiver relacionado com a atribuição, =, em que os dois operandos não têm o mesmo estatuto é um operador membro, para dar resposta a z+=x ou (z+=x)=y, e também para dar resposta a operações de cadeia
public:
Complexo & operator+=( const Complexo & x); //operador membro
//global, mas membro da classe,
Complexo & Complexo::operator+=( const Complexo & x){
a += x.a;
b += x.b;
return *this; //estatuto de referência
}
//a opção agora é global, porque têm o mesmo estatutuo, são consultados apenas
Complexo operator+(const Complexo & x, const Complexo & y){
// const Complexo & -> para funcionar em cadeia, p.e., para responder a z = x + y +z; (exame)
return Complexo( x.getA() + y.getA() , x.getB() + y.getB() );
}
//e global
ostream & operator<<( ostream & saida, const Complexo & x){
// recebe cout: ostream & saida -> é alterado logo usa-se o &, com a informação do objecto
// ostream & operator -> para funcionar em cadeia, p.e., para responder a cout << x << y; (exame)
return saida << “(“<<x.getA() << ” , ” << x.getB() << “)”;
}
para fazer:
z = x + y;
cout << z << endl;
………..os operadores unários:
++
—
que podem ser:
pre-fixados (recomendado que sejam membros), p.e.: ++a, que vai ser interpretada como aa.operator++()
ou
pos-fixados (recomendado que sejam membros), p.e.: a++, que vai ser interpretada como aa.operator++(0)
p.e.:
pre-fixado
public:
Complexo & operator++();
e global
Compelxo & Complexo::operator++(){
a +=1;
retun *this;
}
pos-fixado
public:
Complexo operator++(int);
e global
Compelxo Complexo::operator++(int){
Complexo anterior(a,b); //guardamos o valor velho num outro objecto
a +=1;
retun anterior; //retornamos o velho
}
//neste caso não retrno uma referência
………..operador []
usado em classes, classes com coleções, como arrays ou vectores
operator[]()
x[y] é equivalente x.operator[](y)
serve:
para acedermos a um elemento da coleção, e quebra com o encapsulamento
p.e.:
class Tabela {
static const int DIM = 10;
static double erro;
double a[DIM];
int n; // numero de elementos utilizados
public:
// …
double & operator[](int i);
};
double Tabela::erro = 0;
usando:
double & Tabela::operator[](int i) {
if (i >= 0 && i < DIM) return a[i];
else {
cout << “\nIndice ” << i << ” fora dos limites”;
return erro;
}
}
int main() {
Tabela x;
x[0] = 20; // equivalente a x.operator[](0) = 20;
cout << “\n x[0]=” << x[0] << endl;
x[40] = 55;
}
………..operador chamada de função
usada em situações bidimensionais, por exemplo obter um numero de uma matriz bidimensional
usa dois parentesis curvos
operação tem que ser membro
chama.se usando operator()()
p.e.:
class Matriz {
static const int DIM = 10;
static double erro;
double a[DIM][DIM];
int lin; // numero de linhas utilizadas
int col; // numero de colunas utilizadas
public:
//….
double & operator()(int i, int j);
};
double Matriz::erro = 0;
double & Matriz::operator( )(int i, int j) {
if (i >= 0 && i < DIM && j >= 0 && j < DIM)
return a[i][j]; //com estatuto de referência
else {
cout << “\nIndices i=”
<< i << ” e j=” << j << ” fora dos limites”;
return erro;
}
}
int main() {
Matriz x;
x(1, 0) = 44; // x.operator()( 1,0) = 44; (escrever 44 lá..)
cout << “\n x(1,0)=” << x(1, 0);
x(-1, 100) = 12.1;
}
0 thoughts on “POO, introdução”