• 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

maia@inf.puc-rio.br

(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

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

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 à

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

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) -

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

· 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

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