• Nenhum resultado encontrado

Upcasting Upcasting

N/A
N/A
Protected

Academic year: 2023

Share "Upcasting Upcasting"

Copied!
12
0
0

Texto

(1)

Upcasting Upcasting

Quando o endereço de um objecto derivido (i.e. um ponteiro ou uma referência) é tratado como se fosse o endereço do tipo base, este processo chama-se upcasting.

Exemplo:

aluno a;

empregado e;

pessoa* pa = &a;

pessoa& re = e;

(2)

class pessoa { public:

void anunciar ()

{ cout << "Sou pessoa!" << endl;

}; }

class aluno : public pessoa { public:

void anunciar ()

{ cout << "Sou aluno!" << endl;

}; }

void anuncio (pessoa& p) { p.anunciar();

}

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

{ aluno a1;

anuncio (a1);

return 0;

}

Sou pessoa!

? binding

early late

(3)

Para causar a ligação dinâmica duma função particular usa-se a palavra-chave virtual .

A ligação dinâmica só ocorre para as funções virtuais e desde que seja utilizado o endereço daquela classe base na qual existem estas funções virtuais.

Para criar uma função-membro como virtual, a declaração desta função deve ser precedida pela palavra virtual .

class pessoa { public:

virtual void anunciar ();

};

pessoa.h

void pessoa::anunciar()

{ cout << "Sou pessoa!" << endl;

};

pessoa.cpp

(4)

class pessoa { public:

virtual void anunciar ();

};

pessoa.h

Se uma função é definida como virtual numa classe base, esta função é também virtual em todas as classes derivadas.

class aluno : public pessoa { public:

void anunciar ();

};

aluno.h

void aluno::anunciar()

{ cout << "Sou aluno!" << endl;

};

aluno.cpp void pessoa::anunciar()

{ cout << "Sou pessoa!" << endl;

};

pessoa.cpp

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

{ aluno a1;

anuncio (a1); Sou aluno!

(5)

Extensibilidade

Extensibilidade

void anuncio (pessoa& p) { p.anunciar();

}

Quando anunciar() é definida como virtual na classe base ( pessoa ) torna-se possível adicionar tipos novos (derivados da pessoa ) sem necessidade de modificar a função anuncio() .

class aluno_pos_gr : public aluno { public:

void anunciar ();

};

aluno_pos_gr.h

void aluno_pos_gr::anunciar() {

cout << "Sou aluno de "

"pós-graduação!" << endl;

};

aluno_pos_gr.cpp

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

{ aluno_pos_gr a2;

anuncio (a2);

return 0;

}

Sou aluno de pós-graduação!

Os programas tornam-se extensíveis porque podemos adicionar funcionalidades novas herdando os tipos de dados novos de uma classe base comum.

As funções que manipulam a interface da classe base não precisam

de ser modificadas para poderem suportar as classes novas!

(6)

class aluno_pos_gr : public aluno { public:

void anunciar ();

};

aluno_pos_gr.h

void aluno_pos_gr::anunciar() {

cout << "Sou aluno de "

"pós-graduação!" << endl;

};

aluno_pos_gr.cpp

int main (int argc, char* argv[]) { aluno_doutoramento a3;

anuncio (a2); Sou aluno de pós-graduação!

class doutoramento : public aluno_pos_gr {

};

aluno_doutoramento.h

pessoa aluno

aluno_pos_gr

aluno_doutoramento

(7)

Implementação da ligação dinâmica Implementação da ligação dinâmica

Um compilador típico cria uma tabela (VTABLE) para cada classe que contém funções virtuais.

Nesta tabela põem-se os endereços de todas as funções virtuais desta classe particular.

Em cada objecto da classe com funções virtuais o compilador cria um ponteiro (vpointer) que aponta para a VTABLE deste objecto.

Quando se efectua a chamada de uma função virtual através do ponteiro para a classe base, o compilador gera código que permita aceder ao vpointer e determinar o endereço da função em

VTABLE invocando deste modo a função correcta e causando a

ligação dinâmica.

(8)

class NoVirtual

{ int a;

public:

void x() const {}

int i() const { return 1; } };

class OneVirtual

{ int a;

public:

virtual void x() const {}

int i() const { return 1; } };

class TwoVirtuals

{ int a;

public:

virtual void x() const {}

virtual int i() const { return 1; } };

int main()

{ cout << "int: " << sizeof(int) << endl;

cout << "NoVirtual: " << sizeof(NoVirtual) << endl;

cout << "void* : " << sizeof(void*) << endl;

cout << "OneVirtual: " << sizeof(OneVirtual) << endl;

cout << "TwoVirtuals: " << sizeof(TwoVirtuals) << endl;

int: 4

NoVirtual: 4 void*: 4

OneVirtual: 8

TwoVirtual: 8

(9)

pessoa* A [] = { new pessoa, new aluno, new aluno_pos_gr, new aluno_doutoramento, };

pessoa

vptr

VTABLES:

&pessoa::anunciar Objectos:

aluno

vptr

&aluno::anunciar

aluno_pos_gr

vptr

&aluno_pos_gr ::anunciar

aluno_doutoramento

vptr

&aluno_pos_gr ::anunciar Array de

ponteiros

para pessoa:

(10)

class pessoa

{ public:

virtual void anunciar ()

{ cout << "Sou pessoa!" << endl;

} virtual void print_me();

virtual ~pessoa();

};

class aluno : public pessoa

{ public:

void anunciar ()

{ cout << "Sou aluno!" << endl;

} void print_me();

~aluno();

};

(11)

VTABLE:

Objecto:

aluno

vptr

&aluno :: anunciar ponteiro

para pessoa:

[0]

&aluno :: print_me

[1]

&

aluno

:: ~aluno

[2]

mov ecx,dword ptr [ebp-14h]

call @ILT+160(pessoa::print_me) (004010a5) não virtual:

chamar função pessoa::print_me

aluno a; pessoa& pr = a; pr.print_me();

virtual:

chamar função no endereço VPTR[1]

mov ecx,dword ptr [ebp-14h]

mov edx,dword ptr [ecx]

mov esi,esp

mov ecx,dword ptr [ebp-14h]

call dword ptr [edx+4]

cmp esi,esp

call __chkesp (004038d0)

(12)

O vpointer é inicializado no construtor da classe automaticamente.

O upcasting só funciona com os endereços. Quando o compilador tem o objectos, ele conhece o tipo exacto e portanto não precisa da ligação dinâmica.

int main() {

aluno a;

a.anunciar();

pessoa& pr = a;

pr.anunciar();

pessoa* pp = &a;

pp.anunciar();

return 0;

ligação estática

ligação dinâmica

ligação dinâmica

Overhead

Referências

Documentos relacionados

Escreva um programa que peça ao utilizador o seu apelido e o leia do teclado; depois deve pedir e ler o nome próprio. Na segunda fase deve imprimir no écrân o nome próprio, seguido

Nessa situação temos claramente a relação de tecnovívio apresentado por Dubatti (2012) operando, visto que nessa experiência ambos os atores tra- çam um diálogo que não se dá

Conduziu-se este trabalho com o objetivo de o efeito da formulação N:K com o uso do S na produção de massa seca (MS) e na eficiência da conversão e na recuperação relativa

O Programa do XVII Governo Constitucional consagra, para Portugal, uma estratégia de aproximação aos padrões de abastecimento de água e saneamento de águas residuais

A combinação dessas dimensões resulta em quatro classes de abordagem comunicativa, que podem ser exemplificadas da seguinte forma: interativo/dialógico: professor e

Por ter como objetivo apresentar o desenvolvimento de um índice de competitividade sustentável (ICS) para aplicação ao contexto do BRICS, com a utilização de um

Portugal tem apresentado uma determinada ambição em termos de política externa e de segurança e defesa, tendo sido afirmado publicamente que existe estabilidade nas Forças Armadas

Cozaar Comp é indicado para o tratamento da hipertensão essencial em doentes cuja pressão arterial não está controlada de forma adequada com losartan ou