• Nenhum resultado encontrado

apresentaçãolinguagemC

N/A
N/A
Protected

Academic year: 2021

Share "apresentaçãolinguagemC"

Copied!
299
0
0

Texto

(1)

A Linguagem C++

Renato Maia

[email protected]

(2)

Hello, World!

#include

<iostream>

int main()

{

std::cout << "Hello, world!" << "\n";

}

(3)

MÓDULO I

(4)

Recursos Básicos

n

Parte 1:

¨ Tipos ¨ Declarações ¨ Ponteiros ¨ Vetores ¨ Estruturas ¨ Operadores ¨ Expressões ¨ Comandos ¨ Funções n

Exemplo

¨ Calculadora n

Parte 2:

¨ Espaços de Nomes ¨ Compilação e Ligação

(5)
(6)

Tipo Lógico

n

Tipo: bool

n

Literais: true , false

n

Conversões:

¨

true

è 1

¨

false

è 0

¨

0

è false

¨

?0

è true

(7)

Tipo Caractere

n

Tipo: char

n

Modificadores: signed , unsigned

n

Literais:

¨

Letras: 'a', 'b', ..., 'Z'

¨

Algarismos: '0', '1', ..., '9'

¨

Especiais: '\n', '\t', '\0'

(8)

Tipo Inteiro

n

Tipo: int

n

Modificadores:

¨

signed , unsigned

¨

short , long

n

Literais:

¨

Decimal: 20

¨

Octal: 020

¨

Hexadecimal: 0x20f

(9)

Tipos Reais

n

Tipos: float , double

n

Modificadores: long (aplicável ao double)

n

Literais: (não podem conter espaços)

¨

1.23

¨

.23

¨

1.

¨

1.23e10

(10)

Tipo Vazio

n

Tipo: void

n

Uso:

¨

Como tipo de retorno de uma função

n

Define funções que não retornam valores

¨

Como tipo de ponteiro

n

Define um ponteiro para tipo indefinido (ponteiro

(11)

Enumerações

n

Exemplo:

enum DiaSem { DOM, SEG, TER, QUA, QUI,

SEX, SAB };

n

Uso

¨

Definir um tipo que assume um conjunto de

valores inteiros pré-definidos (enumerados).

(12)
(13)

Declarações

Especificador Tipo Declarador Iniciação/Definição

char ch ;

string s ;

int count = 1 ;

const double pi = 3.1415926535897932385 ;

extern int error_number ;

const char * name = "Najla" ;

const char * season[ ] = {"spring","summer", "fall","winter};

struct Date { int d, m, y } ;

int day(Date* p){ return p->d; } ;

double sqrt(double) ;

template<class T> T abs(T a) { return a<0 ? –a : a; }

typedef list<int> SmallNums ;

struct User ;

(14)

Declarações (observações)

n

Declaração com vários nomes

¨

int a, b = 0;

// apenas o 'b' é iniciado.

¨

int* pa, pb;

// o 'pb' NÃO é um ponteiro.

n

Nomes de identificadores

¨

hello, DEFINED, var23, _123, __,

um_nome_razoavelmente_GRANDE

n

Iniciação (apenas estáticos)

(15)

Escopo

int x = 0;

{

int x = 1;

cout << x;

{

int x = 2;

cout << x;

}

x = 3;

cout << x;

}

cout << x;

(16)

Declaração de Tipos

n

Exemplos:

typedef char *Pchar;

Pchar p1, p2;

char *p3 = p1;

n

Na realidade a declaração de um typedef

define apenas um sinônimo para algum

tipo.

(17)
(18)

Ponteiros

n

Uso

<

Outras Formas

char c = 'a';

char **ppc;

char *pc = &c;

char *vetp[15];

char c2 = *pc;

char (*fp)(char*);

pc:

c: 'a'

&c

(19)

Iniciação de Ponteiros

n

A linguagem C++ não define uma palavra

reservada para indicar um endereço de

memória inválido ou nulo (e.g. null de

Java). Ao invés disso usa-se o valor 0,

que pode ser atribuído a ponteiros.

Nenhum objeto é criado no endereço 0.

(20)

Vetores

n

Dimensões

float d1[3];

float d2[10][20]; // não: float d2[10, 20];

n

Iniciação

int v1[ ] = { 1, 2, 3, 4 }; // v1 é do tipo int[4]

char v3[3] = {'a','b',0}; // não: char v3[2] = {'a','b',0};

int v5[5] = {1,2,3} // equiv.: int v5[3] = {1,2,3,0,0};

int v7[5];

(21)

Literais de Cadeias de Caracteres

n Na iniciação de vetores de caracteres

char c2[ ] = "cadeia";

char c3[ ] = { 'c', 'a', 'd', 'e', 'i', 'a', '\0' }; sizeof("cadeia") == 7

n Acesso através de ponteiros irrestritos (vs. ponteiros para const.)

char *pc = "imutavel";

pc[0] = ' '; // erro: resultado indefinido

n Comparação de cadeias

const char *p = "C++"; const char *q = "C++";

if (p == q) cout << "one!\n"; // depende da implementação do C++

n Quebrando cadeias grandes

(22)

Ponteiros e Vetores

n

Conversão implícita para ponteiros

char v[ ] = "cadeia"; char *p;

p = v; // conversão implícita

v = p; // erro: não é possível atribuir um ponteiro a um vetor

'c' 'a' 'd' 'e' 'i' 'a' 0

v:

p:

p:

(23)

Aritmética de Ponteiros

n

Iteração sobre uma cadeia de caracteres

char v[ ] = "uma cadeia\n"

for (int i = 0

; v[i]

!= 0

; i++

)

use(v[i]);

for (char *p = v

; *p

!= 0

; p++

)

use(*p);

n

Subtração de ponteiros (ou endereços)

int v1[10];

int v2[10];

int i1 = &v1[5] - &v1[3];

// i1 == 2

(24)

Constantes

n

Declaração

const int model = 90;

const int v[ ] = { 1, 2, 3, 4, 5 };

// v[i] é const

const int x;

// erro: exige iniciação

n

Ponteiros constantes

char*const cp;

// ponteiro constante

const char*pc;

// ponteiro para uma constante

(25)

Referências

n

Definição

int i = 1;

int& r = i;

// r e i se referem ao mesmo elemento

n

Uso

int x = r;

// x = 1

r = 2;

// i = 2

n

Iniciação

int& r2;

// erro: falta iniciação

(26)

Ponteiros Genéricos (void *)

n

Recurso de baixo nível

n

Operações

int* pi = &i;

void* pv = pi;// ok: conversão implicita de int* para void*

*pv; // erro: não é possível acessar um void*

pv++; // erro: não é possível incrementar um void*

n

Conversões (cast)

int* pi2 = static_cast<int*>(pv); // conver. explíc.

double* pd1 = pv; // erro

double* pd2 = pi; // erro

(27)
(28)

Estruturas

n

Declaração

struct address {

char *name;

// "Jim Dandy"

long int number;

// 61

char *street;

// "South St"

char *town;

// "New Providence"

char state[2] ;

// ’N’ ’J’

long zip;

// 7974

(29)

Estruturas (cont.)

n

Uso

address jd;

jd.name = "Jim Dandy";

jd.number = 61;

n

Iniciação

address jd = {

"Jim Dandy",

61, "South St",

"New Providence", {´N´,´J´}, 7974 };

(30)

Ponteiro para Estruturas

n

Operador de acesso através de ponteiros

p->m è (*p).m

n

Uso

address *p = &jd

cout

<< p->name << ´\n´

<< p->number << ´ ´ << p->street << ´\n´

<< p->town << ´\n´

<< p->state[0] << p->state[1] << ´ ´

<< p->zip << ´\n´;

(31)

Cópia de Estruturas

address current;

address set_current(address next)

{

address prev = current;

current = next;

return prev;

}

(32)

Declaração Antecipada

struct Link {

Link* previous;

Link* successor;

};

struct List;

// definido posterior.

struct Link {

Link* pre;

Link* suc;

List* member_of;

};

struct List {

Link* head;

};

(33)
(34)

Operadores Relacionais

n

Igual

==

n

Diferente

!=

n

Maior que

>

n

Menor que

<

n

Maior ou igual

>=

n

Menor ou igual

<=

(35)

Operadores Aritiméticos

n

Adição

+

n

Subtração

-n

Multiplicação

*

n

Divisão

/

n

Módulo

%

n

Inversor de sinal

-n

Incremento

--n

Decremento

++

(36)

Operadores Lógicos

n

E (and)

&&

n

Ou (or)

||

(37)

Operadores sobre Bits

n

E bit a bit

&

n

Ou inclusivo bit a bit

|

n

Ou exclusivo (xor) bit a bit

^

n

Complemento

~

n

Deslocamento a esquerda

<<

(38)

Operadores de Atribuição

n Atribuição simples = n Multiplicação e atribuição *= n Divisão e atribuição /= n Módulo e atribuição %= n Soma e atribuição += n Subtração e atribuição -=

n Deslocamento a esquerda e atribuição <<=

n Deslocamento a direita e atribuição >>=

n E bit a bit e atribuição &=

n Ou inclusivo bit a bit e atribuição |=

(39)

Operadores Composicionais

n

Seqüência

<expr> , <expr>

n

Condicional

<cond> ? <true> : <false>

(40)

Operadores de Memória Dinâmica

n

Alocação

new

n

Desalocação

delete

(41)

Operad. de Conversão de Tipos

n

Conversão estática (tipos relacionados)

static_cast<tipo>(valor)

n

Conversão estática (tipos não relacion.)

reinterpret_cast<tipo>(valor)

n

Conversão dinâmica

dynamic_cast<tipo>(valor)

n

Conversão de C

(42)

Operadores de Construção

n

Construtor

tipo (valor)

n

Exemplos

double d = 1.23;

int i = int(d);

complex c = complex(d);

// tipo definido na

biblioteca padrão do C++

(43)

Operadores (observações)

n

Ordem de avaliação dos operandos é indefinida.

int a = f() + g()

// g() pode executar primeiro

n

Sempre use parênteses para garantir a

precedência esperada.

if ( (i & mask) == 0 )

// ...

n

Evite escrever expressões complexas e pouco

legíveis. Conte com as otimizações do

(44)
(45)

Bloco de Comandos

{

<comando>;

<comando>;

<comando>;

...

<comando>;

}

(46)

Comandos de Seleção

n

Condicional

if (<expr>) <comando>;

else <comando>;

n

Seleção

switch (<expr>) {

case <const>:

<comandos>; break;

case <const>:

<comandos>; break;

default:

<comandos>; break;

}

(47)

Comandos de Iteração

n

Laço com teste no início

while (<cond>) <comando>;

n

Laço com teste no final

do <comando> while (<cond>);

n

Laço com contador

for (<início>; <cond>; <increm>) <comando>;

for (;;) { /* ... */ }

// para sempre

(48)

Comando de Salto

n

O famigerado goto

int i;

int j;

for (i = 0; i<n; i++)

for (j = 0; j<m; j++) if (nm[i][j] == a) goto found;

// não encontrado

// ...

found:

(49)
(50)

Definição

extern void swap(int*, int*);

// declaração

void swap(int* p, int* q)

// definição

{

int t = *p;

*p = *q;

*q = t;

}

(51)

Funções inline

inline int fac(int n)

{

return (n<2) ? 1 : n*fac(n-1);

}

int i = f(6);

è

int i = 720;

(52)

Variáveis Estáticas

void f(int a)

{

while (a--)

{

static int n = 0;

// iniciada uma vez

int x = 0;

// iniciada n vezes

cout << "n == " << n++ << ", x == " << x++ << '\n';

}

}

n == 0, x == 0

n == 1, x == 0

n == 2, x == 0

(53)

Passagem de Parâmetros

n

Passagem por referência

void increment(int& aa) { aa++; }; int x = 1; increment(x); // x == 2

n

Parâmetros constantes

void f(const int *p) { *p = 1; /* erro! */ }

n

Parâmetros anônimos

void search(table* t, const char* key, const char*)

{

// não é possível utilizar o terceiro parâmetro

(54)

Constantes por Referência

n

Referência para valores constantes

double& dr = 1; // error: não pode ser constante

const double& cdr = 1; // ok: double t = double(1) ; const double& cdr = t;

n

Valores constantes por referência

void update(float& i) ; void g(double d, float r)

{

update(2.0f) ; // error: argumento constante

update(r) ; // passa uma referência a r

update(d) ; // error: necessária conversão de tipo

(55)

Valor de Retorno

n

Retorno por referência

int vet[5];

int& getcounter(int i) { return vet[i]; }

getcounter(3)++;

n

Retorno de variáveis automáticas

int* fp() { int local = 1;

/* ... */

return &local; }

// cuidado!

(56)

Sobrecarga de Funções

void print(double);

void print(long);

void f()

{

print(1L);

// print(long)

print(1.0);

// print(double)

print(1);

// erro: ambígua, print(long(1)) or

//

print(double(1)) ?

(57)

Parâmetros Default

void print(int value, int base =10); void f() { print(31) ; print(31,16) ; print(31,2) ; } n

Alternativa

void print(int value, int base) ;

inline void print(int value) { print(value,10) ; }

n

Erros comuns

(58)

Parâmetros Variáveis

#include <cstdarg>

void error(int severity, ...) { // "severidade" e mensagens

va_list ap;

va_start(ap, severity) ; // iniciação arg

for (;;) {

char* p = va_arg(ap,char*) ; if (p == 0) break;

cerr << p << ' '; }

va_end(ap) ; // limpa o conteúdo de ap

cerr << '\n';

if (severity) exit(severity) ;

}

(59)

Ponteiros para Funções

void print(const char *s) {

/* ... */

}

void (*pf)(const char*);

// ponteiro para função

void f()

{

pf = print;

// também: pf = &print;

pf("error");

// também: (*pf)("error");

(60)

Macros

n

Substituições simples

#define

PI 3.141593

n

Macros razoáveis

#define

CASE break;case

#define

FOREVER for(;;)

n

Macros perigosas

#define

SQUARE(a) a * a

(61)

Exemplo

(62)

Exemplo

n

Entrada

¨

perimetro = 2 * pi * (r = 2.5)

¨

area = pi * r * r

n

Saída

¨

15.708

¨

19.635

(63)

Gramática da Calculadora

program:

END

expr_list END

expr_list:

expression ;

expression ; expr_list

expression:

expression + term

expression - term

term

term:

term / primary

term * primary

primary

primary:

NUMBER

NAME

NAME = expression

- primary

( expression )

(64)

Tokens

enum Token_value {

NAME, NUMBER, END,

PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',

PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'

};

Token_value

curr_tok = PRINT;

double

number_value;

(65)

Leitura de Tokens

Token_value get_token() {

char ch = 0;

do {

// pula espaços em branco, exceto '\n'

if(!cin.get(ch)) return curr_tok = END;

} while (ch != '\n' && isspace(ch)) ;

(66)

Leitura de Tokens

switch (ch) {

case 0:

return curr_tok = END;

case ';':

case '\n':

return curr_tok = PRINT;

case '*':

case '/':

case '+':

case '-':

case '(':

case ')':

case '=':

return curr_tok = Token_value(ch) ;

(67)

Leitura de Tokens

case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

case '.':

cin.putback(ch) ;

cin >> number_value;

return curr_tok = NUMBER;

(68)

Leitura de Tokens

default: // NAME, NAME=, ou erro

if (isalpha(ch)) {

string_value = ch;

while (cin.get(ch) && isalnum(ch))

string_value += ch ; cin.putback(ch) ;

return curr_tok = NAME;

}

error("bad token") ;

return curr_tok = PRINT;

} }

(69)

Erros

double error(const string& s)

{

no_of_errors++;

cerr << "error: " << s << '\n';

return 1;

(70)

Expressão

double expr(bool get) { // adiciona e subtrai

double left = term(get) ; for(;;) switch (curr_tok) {

case PLUS: left += term(true) ; break; case MINUS: left -= term(true) ; break; default: return left; } }

(71)

Termo

double term(bool get) { // multiplica e divide

double left = prim(get) ; for (;;) switch (curr_tok) {

case MUL: left *= prim(true) ; break; case DIV: if (double d = prim(true)) { left /= d; break; } return error("divide by 0") ; default: return left; }

(72)

Variáveis

n

Armazenar numa tabela que associe

strings a números reais

n

Sugestão: usar o template 'map' da

biblioteca padrão do C++

(73)

Primário

double prim(bool get) { // manipula primários

if (get) get_token() ; switch (curr_tok) {

case NUMBER: // constante real

{ double v = number_value; get_token() ; return v; } case NAME: { double& v = table[string_value] ;

if (get_token() == ASSIGN) v = expr(true) ; return v;

(74)

Primário

case MINUS: // menos unário

return -prim(true) ; case LP:

{ double e = expr(true) ;

if (curr_tok != RP) return error(") expected") ;

get_token() ; // consome o ')'

return e;

}

default:

return error("primary expected") ;

} }

(75)

Função main

int main(int argc, char* argv[])

{

table["pi"] = 3.1415926535897932385; // constantes predefinidas

table["e"] = 2.7182818284590452354;

while (cin) {

get_token() ;

if (curr_tok == END) break;

if (curr_tok == PRINT) continue;

cout << expr(false) << '\n'; }

return 0;

(76)

Exercícios

1.

Compilar e executar o programa de exemplo mostrado

previamente

2.

Escrever um programa de encriptação que recebe um

texto pela entrada padrão (cin) e devolve um texto

codificado na saída padrão (cout).

¨ A codificação deve ser feita na forma c^chave[i], tal que chave é uma string dada pela linha de comando. Dessa forma quando um texto for novamente codificado com a mesma chave o texto original é recuperado.

¨ Os caracteres da chave devem ser utilizados de forma circular.

¨ Se nenhuma chave for fornecida, então nenhuma codificação deve ser feita.

(77)

Teste do Exercício 2

n

Legenda:

¨

encrypt:

nome do seu programa

¨

senha:

chave de criptografia

¨

input.txt:

um arquivo de texto qualquer

¨

output.dat:

arquivo com o texto codificado

¨

back.txt:

arquivo com o texto decodificado

n

Comandos:

C:\>encrypt senha < input.txt > output.dat

C:\>encrypt senha < output.dat > back.txt

(78)
(79)

Espaços de Nomes

namespace Parser { double expr(bool) ;

double prim(bool get) { /* ... */} double term(bool get) { /* ... */} double expr(bool get) { /* ... */} }

namespace Lexer { enum Token_value {

NAME, NUMBER, END,

PLUS=´+´, MINUS=´-´, MUL=´*´, DIV=´/´, PRINT=´;´, ASSIGN=´=´, LP=´(´, RP=´)´ }; Token_value curr_tok; double number_value; string string_value; Token_value get_token() { /* ... */} }

(80)

Nomes Qualificados

double Parser::term(bool get) // note a qualificação Parser::

{

double left = prim(get) ; // nenhuma qualificação necessária

for (;;)

switch (Lexer::curr_tok) { // note a qualificação Lexer::

case Lexer::MUL: // note a qualificação Lexer::

left *= prim(true) ; // nenhuma qualificação necessária // ...

}

// ...

(81)

Utilizando Declarações

namespace Parser {

double term(bool get);

// ...

using Lexer::curr_tok; // use o curr_tok do Lexer

}

double Parser::term(bool get) { double left = prim(get);

for (;;) switch (curr_tok) { // qualificação Lexer:: é desnecessária

case Lexer::MUL: left *= prim(true) ; // ... } // ... }

(82)

Diretivas de Utilização

namespace Parser {

double term(bool get);

// ...

using namespace Lexer; // incorpora todas as declarações

}

double Parser::term(bool get) { double left = prim(get);

for (;;) switch (curr_tok) { // qualificação Lexer:: é desnecessária

case MUL: // qualificação Lexer:: é desnecessária

left *= prim(true) ;

// ...

}

// ...

(83)

Espaços de Nomes Anônimos

namespace { int a; void f() { /* ... */ } int g() { /* ... */ } } /* Equivalente a: namespace $$$ { int a; void f() { /* ... */ } int g() { /* ... */ } } using namespace $$$; */

(84)

Alias de Espaços de Nome

// nome muito longo

namespace American_Telephone_and_Telegraph { /* ... */ } American_Telephone_and_Telegraph::String s3 = "Grieg"; American_Telephone_and_Telegraph::String s4 = "Nielsen";

// alias

namespace ATT = American_Telephone_and_Telegraph;

ATT::String s3 = "Grieg"; ATT::String s4 = "Nielsen";

(85)

Exercício

n

Dividir o programa de exemplo da calculadora

em módulos (usando espaços de nomes)

¨

Módulo Léxico (namespace Lexer)

n Leitura e interpreção de tokens

¨

Módulo Parser (namespace Parser)

n Interpretação e avaliação de expressões

¨

Módulo de Erros (namespace Error)

(86)

Compilação e

Ligação

(87)

Compilação Condicional

#ifdef NDEBUG

const bool ARG_CHECK = false; // desabilita verificações

#else

const bool ARG_CHECK = true; // habilita verificações

#endif

void f3(int* p)

{

assert(!ARG_CHECK || p!=0) ; // ou não faz verificação ou p!=0 // ...

(88)

Compilação em Partes

lexer.cpp

parser.cpp

error.cpp

main.cpp

<string>

<map>

lexer.h

parser.h

error.h

(89)

Cabeçalho do Módulo Lexer

#include <string>

namespace Lexer {

enum Token_value {

NAME, NUMBER, END,

PLUS = '+', MINUS = '-', MUL = '*', DIV = '/', PRINT = ';', ASSIGN = '=', LP = '(', RP = ')' };

extern Token_value curr_tok; extern double number_value; extern std::string string_value;

Token_value get_token(); }

(90)

Módulo Lexer

#include "lexer.h" #include "error.h" #include <iostream> #include <cctype> using std::cin;

Lexer::Token_value Lexer::curr_tok = Lexer::PRINT;

double Lexer::number_value;

std::string Lexer::string_value;

(91)

Guardas de Inclusão

n

Para evitar que um cabeçalho seja incluído diversas

vezes no mesmo arquivo

// error.h: #ifndef CALC_ERROR_H #define CALC_ERROR_H namespace Error { // ... } #endif // CALC_ERROR_H

(92)

Ligação com Código C

n A forma de chamada de funções C é diferente das chamadas de C++. É necessário informar ao compilador quando uma função deve ser ligada como uma função C.

extern "C" void funcao_c(int, int); extern "C" {

void uma_funcao_c(int, int);

void outra_funcao_c(int, double); void mais_outra_funcao_c(char*);

}

extern "C" {

#include "modulo_c.h" }

(93)

Ponteiros para Funções C

typedef int (*FT)(const void*, const void*) ; // FT tem ligação C++

extern "C" {

typedef int (*CFT)(const void*, const void*) ; // CFT tem ligação C

void qsort(void* p, size_t n, size_t sz,CFT cmp) ; // cmp tem ligação C

}

void isort(void* p, size_t n, size_t sz,FT cmp) ; // cmp tem ligação C++

void xsort(void* p, size_t n, size_t sz,CFT cmp) ; // cmp tem ligação C

extern "C" void ysort(void* p, size_t n, size_t sz,FT cmp) ; // cmp tem ligação C++

int compare(const void*, const void*) ; // compare() tem ligação C++

extern "C" int ccmp(const void*, const void*) ; // ccmp() tem ligação C

void f(char* v, int sz) {

qsort(v,sz,1,&compare) ; // erro

qsort(v,sz,1,&ccmp) ; // ok

isort(v,sz,1,&compare) ; // ok

isort(v,sz,1,&ccmp) ; // erro

(94)

Exercício

n

Dividir o programa de exemplo da

calculadora em unidades de compilação

diferentes (usando a mesma estrutura de

módulos do último exercício)

¨

Módulo Léxico (lexer.cpp e lexer.h)

¨

Módulo Parser (parser.cpp e parser.h)

¨

Módulo de Erros (error.cpp e error.h)

¨

Módulo Principal (main.cpp)

(95)

MÓDULO II

(96)

Mecanismos de Abstração

n

Parte 1:

¨

Classes

¨

Objetos

n

Parte 2:

¨

Sobrecarga de

Operadores

¨

Classes Derivadas

n

Parte 3:

¨

Herança Múltipla

¨

Templates

n

Parte 4:

¨

Exceções

¨

Informação de Tipo

Dinâmica (RTTI)

(97)
(98)

Classes

n

As classes de C++ define um novo tipo

que funcionam como um tipo básico da

linguagem

n

A forma de usar um objeto de uma classe

não deve diferir do uso dos tipos básicos

(99)

Funções Membro

class Date {

int d,m,y;

void init(int dd, int mm, int yy) ; void add_year(int n) { y += n; }

void add_month(int n) { m += n; } void add_day(int n) { d += n; } };

void Date::init(int dd, int mm, int yy) { // especifica a classe a que pertence

d = dd; m = mm; y = yy; }

(100)

Controle de Acesso

class Date {

int d,m, y;

// privado: acessível por funções membro

public:

// público: acessível por qualquer cliente

void init(int dd, int mm, int yy) ;

void add_year(int n)

{ y += n; }

void add_month(int n) { m += n; }

void add_day(int n)

{ d += n; }

};

(101)

Classes e Estruturas

n

Estruturas são equivalentes a classes, sendo que o

controle de acesso padrão é o público.

struct X { // ... }

Equivalente a:

class X { public: // ... }

(102)

Importância Controle Acesso

n

Erros que causam inconsistência de dados

privados são localizados na implementação das

funções membro de acesso

n

Alterações na implementação não são

propagadas aos clientes

n

Simplifica a utilização da classe, pois é

(103)

Construtores

class Date {

int d,m, y; public:

Date(int dd=0,int mm=0,int yy=0);

// ...

};

Date::Date(int dd, int mm, int yy) {

d = dd ? dd : today.d; m = mm ? mm : today.m; y = yy ? yy : today.y;

// verifica de a data é válida

}

n Inicição de objetos Date Date today(22) ;

Date july4(4, 7, 1983) ; Date birthday(4, 12) ; Date now;

(104)

Membros Estáticos

class Date {

int d,m, y;

static Date today; public:

Date(int dd=0,int mm=0,int yy=0);

// ...

static void settoday(int, int, int);

};

Date Date::today(17, 11, 2004);

void Date::settoday(int d,int m,int y){

today = Date(dd, mm, yy) }

n Acesso a membros estáticos Date now;

now.settoday(22, 11, 2004); ou

(105)

Auto-Referência

n

Todo objeto tem um ponteiro implícito

demominado this que aponta para o próprio

objeto

bool Date::is_the_same(Date& other)

{

return *this == other;

(106)

Funções Membro Constantes

n Não alteram os estado do objeto

class Date { int d,m, y; public:

int day() const { return d++; } // erro: tentativa de alteração do estado

int month() const;

// ...

};

inline int Date::month() const { return m; }

n Podem ser chamadas a partir de referências constantes

const Date my_date(12, 4, 1865);

cout << my_date.day() << "/" << my_date.month() << "/" << my_date.year()

(107)

Membros Mutáveis

n Alteração de membros através de funções membro

constantes

string Date::string_rep() const { if (!cache_valid) { compute_cache() ; cache_valid = true; } return cache; } class Date {

mutable bool cache_valid; mutable string cache;

void compute_cache() const;

// ...

public:

// ...

string string_rep() const; };

(108)

Funções Auxiliares

n

É possível definir funções auxiliares para manipular

objetos

int diff(Date a,Date b) ; bool leapyear(int y) ;

Date next_weekday(Date d) ; Date next_saturday(Date d) ;

n

Função membro vs. função auxiliar

¨ Função membro acessa diretamente o estado privado do objeto

¨ Função auxiliar realiza sua tarefa apenas com as operações da interface pública do objeto.

(109)

Funções Amigas

class Matrix; class Vector {

float v[4] ;

// ...

friend Vector multiply( const Matrix&, const Vector&) ; }; class Matrix { Vector v[4] ; // ...

friend Vector multiply( const Matrix&, const Vector&) ;

};

n Permite acessar a interface privada das classes

Vector multiply( const Matrix&m, const Vector& v ) {

Vector r;

for (int i = 0; i<4; i++) { // r[i] = m[i] * v;

r.v[i] = 0; for (int j = 0; j<4; j++) r.v[i] +=m.v[i].v[j] * v.v[j] ; } return r; }

(110)

Funções Amigas

n

Funções Membro

class List_iterator { // ... int* next() ; }; class List {

friend int* List_iterator::next() ;

// ...

};

n

Classes Amigas

class List {

friend class List_iterator;

// ...

};

¨ Todas funções membro de List_iterator se tornam amigas da classe List

(111)

Exercício

n

Implementar o tipo Date, como ilustrado nos

exemplos anteriores:

¨

Construtor default

¨

Definir o valor da data default

n Use uma abordagem similar à função Date::settoday()

¨

Funções para acesso aos dados

n Dia, mês e ano

¨

Funções para adicionar dias, meses e anos

(112)
(113)

Criação e Destruição

n

Sempre que um objeto não é mais

utilizado, ele deve ser destruído

n

Assim como a inicialiação (ou construção)

de objetos, a destruição pode ser feita

automaticamente pelo compilador ou pode

ser feita explicitamente

(114)

Destrutores

struct cache { bool valid; string rep; }; class Date { cache* c;

void compute_cache () const;

// ...

public:

Date(int dd=0,int mm=0,int yy=0); ~Date(); // destrutor

// ...

string string_rep() const; };

n Libera os recursos alocados durante a construção do objeto

Date::Date(int dd,int mm,int yy) { c = new cache; c->valid = false; // ... } Date::~Date() { delete c; }

(115)

Cópia Default

n

Operação de cópia default

void apaga(Date *dia) {

Date copia = *dia;// copia.c = dia->c; copia.d = dia->d; ...

delete dia; // destrói o objeto, apaga 'c'

cout << "O dia " << copia.string_rep() << "foi apagado\n"; // erro

}

(116)

Variáveis Locais

n Construção:

¨ Fluxo de execução encontra a declaração da variável n Destruição

¨ Variável sai do escopo

n Exemplo void f(int i) { if (i>0) { Date aa; // ... } Date bb; // ... }

(117)

Memória Dinâmica

n Construção

¨ Explicitamente através do operador new

Date *d = new Date(22, 11, 2004);

n Destruição

¨ Explicitamente através do operador delete

delete d;

n Cuidados

¨ Objetos destruídos

delete dia;

delete dia; // erro

¨ Brechas de memória (memory leaks)

void hoje() {

Date *dia = new Date();

cout << "Hoje é dia " << dia.string_rep() << "\n"; }

(118)

Membros de Classes

n Construção

¨ Na construção do objeto a que pertence, na ordem que aparecem na declaração.

n Destruição

¨ Na destruição do objeto o que pertence , na ordem inversa da que aparecem na declaração.

n Inicialização de Membros

class DaySequence { const int days;

Date start; public:

DaySequence(const Date& s, const int i) : days(i), start(s) { } }

(119)

Vetores

n

Construção

¨ Na criação do vetor

¨ Apenas é permitido para tipos com um construtor sem parâmetros

n

Destruição

¨ Na destruição do vetor n

Exemplo

Date vds[10];// cria 10 objetos usando o construtor Date::Date()

Date vdd[10] = new Date[10];

(120)

Variáveis Locais Estáticas

n Construção

¨ Fluxo de execução encontra a declaração da variável pela primeira vez.

n Destruição

¨ Termino do programa

n Exemplo

// Declaração das variáveis // Construção dos objetos

void f(int i) { f(0); // d1 é construído

static Date d1; f(1); // apenas o d2 é contruído // ... f(2); // nenhum dos objetos é criado

if (i) {

static Date d2;

// ...

} }

(121)

Não Locais

n Variáveis não locais:

¨ Variáveis globais

¨ Variáveis em espaços de nomes

¨ Variáveis estáticas de classe

n Construção

¨ Antes no início da função main

¨ Na ordem que suas definições aparecem

n Destruição

¨ Após o término da função main

¨ Na ordem inversa que suas definições aparecem

n Exemplo

class X { static Date memdate; }; // apenas a definição do membro estático

Date date; // declaração de variável global

Date X::memdate; // declaração do membro estático da classe X

(122)

Objetos Temporários

n Construção

¨ Na avaliação da expressão que os criam n Destruição

¨ Ao final da avaliação da expressão que os criam

n Exemplo

void f(string& s1, string& s2, string& s3)

{

const char* cs= (s1+s2).c_str() ;

cout << cs; // problema: cs aponta para uma área desalocada

if (strlen(cs=(s2+s3).c_str())<8 && cs[0]==´a´) { // ok // qualquer uso de cs aqui é inválido

} }

(123)

Exercício

n Implementar o tipo Table, que deve oferecer a seguinte interface:

struct Name {

enum Gender { male, female } const char* s; Gender g; }; class Table { Name* p; size_t sz; int c; public: Table(size_t s = 15); ~Table();

Name* lookup(const char *) ;

bool insert(Name&) ;

(124)

Sobrecarga de

Operadores

(125)

Operadores Disponíveis

n

Operadores que podem ser redefinidos

+- * / % ^ &

| ~ ! = < > +=

-= *= /= %= ^= &= |=

<< >> >>= <<= == != <=

>= && || ++ -- ->* ,

-> [] () new new[] delete delete[]

n

Operadores que NÃO podem ser redefinidos

:: (Resolução de escopo) . (Seleção de membros)

(126)

Funções Operadoras

n

Função Membro

class complex {

double re, im;

public:

complex(double r, double i=0) : re(r) , im(i) { }

complex operator+(complex) ;

};

n

Função Auxiliar

(127)

Casamento de Função Operador

n

Escolha da função operador para um

operador @

¨

Operadores Binários (a@b)

a.operator@(b)

ou

::operator@(a, b)

¨

Operadores Unários (a@)

(128)

Exemplos de Sobrecarga de

Operadores

class X {

// members (with implicit 'this' pointer):

X* operator&() ; // & unário (endereço de)

X operator&(X) ; // & binário (e bit a bit)

X operator++() ; // incremento prefixo

X operator&(X,X) ; // erro: ternário

X operator/() ; // erro: / unário

};

// nonmember functions:

X operator-(X) ; // menos unário

X operator-(X,X) ; // menos binário

X operator--(X&,int) ; // decremento posfixo

X operator-(); // erro: nenhum operando

X operator-(X,X,X) ; // erro: ternário

(129)

Significados Predefinidos

n As funções operator=, operator[], operator() e operator-> devem ser definidas como funções membro não estáticas

n Apenas alguns operadores já possuem um significado predefinido

= (atribuição, faz cópia dos valores dos membros) & (endereço de, retorna o endereço do objeto)

, (seqüência, retorna o valor do segundo parâmetro)

n Entretanto, esses significados podem ser redefinidos através da sobrecarga de operadores

(130)

Cópia de Objetos

n Construtor de cópia

Date::Date(const Date& other) { // exemplo:

c = new cache; // Date copia = data;

c->valid = false;

d = other.d; m = other.m; y = other.y; }

n Operador de atribuição

Date::operator=(const Date& other) { // exemplo:

if (*this != other) { // Date copia(2, 4, 1876);

delete c; // copia = data;

c = new cache; c->valid = false;

d = other.d; m = other.m; y = other.y; }

(131)

Procura pela Implementação de

Operadores

n Considere a expressão x@y, (x é do tipo X e y é do tipo Y)

¨ Se X é uma classe e define operator@ como um membro essa função membro como operadora

¨ Caso contrário

n Procura por declarações de operator@ no contexto de x@y

n Adicinonalmente, se X é definido num espaço de nomes N, procura por

declarações de @ em N

n Adicinonalmente, se Y é definido num espaço de nomes M, procura por

declarações de @ em M.

Neste último caso, todas as declarações de operator@ são levadas em consideração para determinar a que se adequa a expressão.

n As mesmas regras para casamento de funções sobrecarregadas são aplicadas a operadores.

(132)

Conversões Implícitas

bool operator==(complex,complex) ;

void f(complex x, complex y)

{

x==y; // significa operator==(x,y)

x==3; // significa operator==(x,complex(3))

3==y; // significa operator==(complex(3),y)

}

(133)

Operadores de Conversão

Explícita

class Tiny { char v;

void assign(int i) { if (i&~077) v=0; else v=i; } public:

Tiny(int i) { assign(i) ; }

Tiny& operator=(int i) { assign(i) ; return *this; }

operator int() const { return v; } // conversão para int

};

n Atenção

Tiny::operator int() const { return v; } // certo

(134)

Ambigüidades

n Sempre que a combinação de construtores e operadores de conversão gerarem ambiguidade na resolução de funções sobrecarregadas, o compilador informará o erro.

n Tome cuidado com conversões inesperadas (ou a falta delas)

class Quad { public: Quad(double) ; // ... }; Quad operator+(Quad,Quad) ;

void f(double a1, double a2)

{

Quad r1 = a1+a2; // adição com precisão dupla

Quad r2 =Quad(a1)+a2; // força aritmética da classe quad

(135)

Construtores Explícitos

n

Considere

complex z = 2; // inicializa z com complex(2)

String s = 'a'; // cria uma string com int('a') elementos

n

Solução

class String {

// ...

explicit String(int n) ; // prealoca n bytes

String(const char* p) ; // valor inicial é uma string C

string p };

(136)

Operador de Indexação

class Assoc { struct Pair {

string name; double val;

Pair(string n ="", double v =0) :name(n) , val(v) { }

};

vector<Pair> vec;

// privado para prevenir cópia

Assoc(const Assoc&) ;

Assoc& operator=(const Assoc&) ;

public:

Assoc() {}

double& operator[](const string&) ; void print_all() const;

};

double& Assoc::operator[](const string& s) {

vector<Pair>::iterator p=vec.begin();

for (; p!=vec.end(); ++p)

if (s == p->name) return p->val;

vec.push_back(Pair(s,0)) ;

return vec.back().val;

}

void Assoc::print_all() const {

vector<Pair>::const_iterator p=vec.begin();

for (; p!=vec.end(); ++p)

cout << p->name << ": " << p->val << ´\n´; }

(137)

Operador de Chamada de Função

class Add {

complex val;

public:

Add(complex c) { val = c; } // salva o valor

Add(double r, double i) { val = complex(r,i) ; }

void operator()(complex& c) const { c += val; } // adiciona valor

};

complex vc[10];

void for_each(Add& func) { for (int i = 0; i < 10; i++) func(vc[i]); } void main() {

Add func(2, 3); for_each(func); }

(138)

Operador de Dereferência

n

Declaração (operador unário)

class Ptr { /* ... */ X* operator->(); }; n

Transformação

void f(Ptr p) { p->m = 7; // (p.operator–>())–>m = 7 } n

Uso

void g(Ptr p) { X* q1 = p->; // erro de sintaxe X* q2 = p.operator->();// ok }

(139)

Operadores Unários Posfixos

class Ptr_to_T { T* p; T* array; int size; public:

Ptr_to_T(T* p, T* v, int s) ; // associa a pos. p do vetor v de tam. s

Ptr_to_T& operator++() ; // prefixo

Ptr_to_T operator++(int) ; // posfixo

Ptr_to_T& operator--(); // prefixo

Ptr_to_T operator--(int) ; // posfixo

T&operator*() ; // prefixo

(140)
(141)

Classes Derivadas

class Employee { string name; Date hiring_date; shot department; // ... public:

void print() const;

string get_name() const {

return name; }

// ...

};

class Manager : public Employee {

set<Employee*> group;

short level;

// ...

public:

void print() const;

// ...

(142)

Estrutura de Objetos

Employee:

name

department

...

name

department

...

group

level

...

Manager:

(143)

Polimorfismo

void f(Manager m1, Employee e1) {

list<Employee*> elist; elist.push_front(&m1); elist.push_front(&e1); }

void g(Manager mm, Employee ee) {

Employee* pe= &mm; // ok: todo Gerente é um Empregado

Manager* pm= &ee; // erro: nem todo Empregado é um Gerente

pm->level = 2; // desastre: ee não tem um 'level'

pm = static_cast<Manager*>(pe) ; // força bruta, mas funciona

pm->level = 2; // ok: pm aponta para mm que tem um 'level'

(144)

Implement. de Funções Membro

n Não é possível acessar membros privados em classes derivadas

void Manager::print() const {

cout << "Name: "<< name << '\n'; // erro: name é privado

cout << "\tDept:\t"<< department << '\n'; // erro: department é privado

cout << "\tLevel:\t" << level << '\n';

cout << "\tTeam:\t" << group.size() << '\n'; }

n É necessário usar a interface pública (e protegida, i.e. protected)

void Manager::print() const {

Employee::print(); // cuidado: print() não qualificado causa recursão

cout << "\tLevel:\t" << level << '\n';

cout << "\tTeam:\t" << group.size() << '\n'; }

(145)

Controle de Acesso

n

Escopo Privado (private)

¨

Nomes podem ser usados em funções membro e

funções amigas da classe.

n

Escopo Protegido (protected)

¨

Nomes podem ser usados em funções membro e

funções amigas da classe e nas funções membro e

funções amigas das suas classes derivadas.

n

Escopo Público (public)

(146)

Acesso a Membros Herdados

n

class X : public B {

/* ... */

};

¨ Acesso aos membros públicos e protegidos de B e conversão de X* para B* só pode ser feito em funções membro e amigas de X.

n

class Y : protected B {

/* ... */

};

¨ Acesso aos membros públicos e protegidos de B e conversão de Y* para B* só pode ser feito em funções membro e amigas de Y e de suas classes derivadas.

n

class Z : private B {

/* ... */

};

¨ Acesso aos membros públicos de B e conversão de Z* para B* só pode ser feito pode ser feito de qualquer função.

Adicionalmente, o acesso aos membros protegidos de B só pode ser feito em funções membro e amigas de Z e de suas classes derivadas.

(147)

Construção

n Classe Base

Employee(const string& n, int d) : name(n), department(d)

{

// …

}

n Classe Derivada

Manager(const string& n, int d, int lvl)

: Employee(n, d), level(lvl) // não é possível iniciar diretamente // os membros de Employee

{

// …

(148)

Cópia Fatiada

n

Exemplo

void f(const Manager& m) {

Employee e = m; // constrói e a partir da parte Employee de m

e = m; // atribui a parte Employee de m a e

}

n

Cuidado

void slice_copy(Employee ee) {

ee.print(); }

// ...

Manager m("John Gee", 1, 4);

(149)

Funções Virtuais

n

Definição

class Employee {

// ...

virtual void print() const;

};

n

Exemplo

void virtual_call(Employee* ee) {

ee->print(); // a função print adequada é chamada

}

// ...

Manager m("John Gee", 1, 4); virtual_call(&m);

(150)

Classes Abstratas

n Permite definir classes com funções sem implementação

class Shape { public:

// funções virtuais puras

virtual void rotate(int) = 0; virtual void draw() = 0; virtual bool is_closed() = 0;

// ...

};

n Não é possível criar objetos de classes abstratas

Shape s; // erro: Shape é abstrata

n Classes abstratas somente são utilizadas como classe base

class Point { /* ... */ };

class Circle : public Shape { public:

// define funções virtuais herdadas

void rotate(int) { } void draw() ;

bool is_closed() { return true; }

Circle(Point p, int r) ;

private:

Point center;

int radius;

(151)

Ponteiros para Membros

struct Class {

const char* memb_data;

virtual void memb_func() = 0;

};

typedef void (Class::*PMF)() ; // tipo ponteiro para função membro

typedef const char* Class::*PMD; // tipo ponteiro para membro de dado

void f(Class* p) {

PMF pmf = &Class::memb_func(); p->memb_func() ; // chamada direta

(p->*pmf)() ; // chamada através de ponteiro para membro

PMD pmd = &Class::memb_data; p->memb_data() ; // acesso direto

p->*pmd = "string" ; // acesso através de ponteiro para membro

(152)

Propósito de Classes Concretas

n

Classes concretas são usadas para definir novos tipo

(e.g. classe Date) que façam tarefas simples e de forma

eficiente.

n

Se o comportamento de uma classe concreta não é

adequado, uma nova classe deve ser construída. Se

possível utilizando a classe concreta, da mesma forma

se utiliza um int na classe Date.

n

Sempre tente definir um bom conjunto de tipos como

base da sua aplicação e defina esses tipos através de

classes concretas

(153)
(154)

Problema

n

Suponha um sistema de simulação onde cada

elemento simulado realiza uma tarefa e possui

uma representação visual dessa tarefa.

n

Cada elemento tem o comportamento de uma

tarefa e de algo visual.

n

Definimos duas classes:

¨

Task: define o comportamento relativo a execução de

uma tarefa

¨

Displayed: define o comportamento relativo a

exibição visual de informações

(155)

Solução com Herança Múltipla

n Para cada elemento simulado a sua repesentação visual (Displayed) é muito

dependente da sua tarefa (Task).

n A implementação da

simulação de um satélite pode ser feita numa única classe que herde as interfaces e implementações fornecidas pelas classes Task e

Displayed. Task dados funções Displayed dados funções Satellite dados funções

(156)

Herança Múltipla

n

Classe com herança múltipla

class Satellite : public Task, public Displayed {

// ...

};

n

É possível acessar membros das duas classes base

void f(Satellite& s) {

s.draw() ; // Displayed::draw()

s.delay(10) ; // Task::delay()

s.transmit() ; // Satellite::transmit()

(157)

Herança Múltipla

n

Objetos de classes com herança múltipla de comportam

como um objeto de cada classe base

void highlight(Displayed*) ;

void suspend(Task*) ;

void g(Satellite* p) {

highlight(p) ; // passa um ponteiro para a parte Displayed

suspend(p) ; // passa um ponteiro para a parte Task

(158)

Resolução de Ambigüidade

class Task {

// ...

virtual debug_info* get_debug() ;

};

class Displayed {

// ...

virtual debug_info* get_debug() ;

};

void f(Satellite* sp) {

debug_info* dip = sp->get_debug() ; // erro: ambíguo

dip = sp->Task::get_debug() ; // ok

dip = sp->Displayed::get_debug() ; // ok

(159)

Redefinição de Membros

n

Definir na classe derivada o comportamento adequado

class Satellite : public Task, public Displayed {

// ...

debug_info* get_debug() // defefine Task::get_debug() e // Displayed::get_debug()

{

debug_info* dip1 = Task::get_debug() ;

debug_info* dip2 = Displayed::get_debug() ;

return dip1->merge(dip2) ;

} };

(160)

Classes Base Duplicadas

struct Link {

Link* next; };

class Task : public Link {

// o Link é usado para manter // a lista de todas Tasks.

// ...

};

class Displayed : public Link {

// o Link é usado para manter // a lista de todos Displayed. // ... }; Task dados funções Displayed dados funções Satellite dados funções Link dados funções Link dados funções

(161)

Classes Base Duplicadas

n

Atenção:

void insert_before(Satellite* s, Task* t, Displayed* d)

{

s->next = t.next;

// erro: ambíguo

s->Task::next = t.next;

s->Displayed::next = d.next;

t.next = s;

d.next = s;

}

Referências

Documentos relacionados

Assim como para as equações, no estudo das inequações devemos, primeiramente, definir uma inequação para que, em seguida, possamos trabalhar com um tipo de inequação chamada

Toxicidade reprodutiva: Com base nos dados disponíveis, os critérios de classificação não são preenchidos. Toxicidade para órgãos-alvo específicos (STOT) -

· Indicações sobre cuidados médicos urgentes e tratamentos especiais necessários Não existe mais nenhuma informação relevante disponível.. 5 Medidas de combate

Assumindo a estrutura Ponto2d vista em aula, a estrutura para o segmento de reta seria a seguinte:.. typedef

Assim, 50,0% citam a palavra “polinização” uma ou mais vezes, demostrando conhecimento sobre o serviço ecossistêmico que as abelhas prestam ao meio ambiente e

O que se sabe é que temos muito tempo ainda para esta decisão e Rossoni pode mudar de ideia e partir novamente para carreira estadual, pois o nome de Beto Richa na disputa à

O termo ressuscitação com volumes pequenos foi relatado por Nakayama et al., 1984 13 , em um modelo experimental de choque hemorrágico, utilizando ove- lhas, no qual houve

Vídeo Capa ou Foto de Capa - Possibilidade de exibir uma foto de capa no estande do expositor bem como um vídeo ou transmissão ao vivo (ideal para exibição de produto).. Inserção