next up previous contents index
Next: Ferramentas Up: O Nível de Previous: Representação de Tipos

Invocação de Operações Sobre a Carta

 

Em funcionamento normal, os envelopes apenas redireccionam os pedidos de invocação, vindos do exterior do objecto composto, para a carta. Esta seria um modo de operação trivial se não pudessem ocorrer conversões de tipos nem existisse herança múltipla. O primeiro aspecto dificulta o processo de selecção de métodos. O segundo, além de ter as mesmas consequências que o primeiro, requer, no caso geral, a modificação de this em tempo de execução.

A utilização de herança múltipla, eventualmente associada a polimorfismo, constitui um aspecto crítico para o correcto funcionamento das invocações, obrigando à dedicação de especial atenção aos problemas que surgem com conversões de tipos e utilização indiscriminada dos vários tipos de polimorfismo disponíveis em C++, assim como das várias modalidades de herança. Esta, mesmo podendo não ser múltipla, pode apresentar dificuldades, e.g. herança virtual.

Se existir herança múltipla na hierarquia de cartas ela é replicada na hierarquia de envelopes, tal como acontece no caso de herança simples. Se existirem múltiplas raízes, cada uma delas derivará, virtualmente da classe SPM_quotLL_Envelope", tal como é ilustrado na figura 6.2.

  
Figure 6.2: Ancoragem da hierarquia em LL_Envelope.

Quer no caso de herança simples, quer no de herança múltipla, todas as decisões de selecção de métodos a executar, passam a ser irrelevantes para a hierarquia de cartas, passando a ser da exclusiva responsabilidade da hierarquia de envelopes.

Cada envelope invoca, de forma directa, através de qualificação explícita, o método correspondente da carta. O exemplo abaixo mostra um método de um envelope, onde se pode ver como se processa uma invocação deste estilo. A invocação directa obriga que a carta esteja perfeitamente emparelhada com o respectivo envelope, isto é devem corresponder a classes correspondentes na hierarquias paralelas. A razão deve-se ao facto de o envelope, quando recebe uma invocação, realizar uma dupla conversão de tipos antes de invocar o método da carta. A conversão pode produzir dados erróneos se não se verificar a condição relativa ao emparelhamento.

        // Código do envelope da classe Line...
        virtual void Insert(char c)
        {
            ((LineLetter *)((letter.typeid == __LineLetter__TypeName)
                ? ((LineLetter *)letter.letter)
                : (void *)0))->LineLetter::Insert(c);
        }

O código do método realmente gerado pela ferramenta que produz os envelopes é uma chamada a uma macro, que se apresenta abaixo, e que permite definir métodos arbitrários numa classe de envelopes. No caso ilustrado acima, a chamada seria SPM_quotLETENV_METHOD(Line, Insert, c)". A macro esconde pormenores sobre a hierarquia de classes através da chamada a SPM_quotSPELLCAST". A sua expansão depende fortemente da classe onde é utilizada.

#define LETENV_METHOD(type,method,args...)                            \
{                                                                     \
    if (!client.letter) SPELLCAST(type##Letter,letter)::method(args); \
    else SPELLCAST(type##Client,client)::method(this , ##args);       \
}

#define SPELLCAST(type,obj) ((type*)DYN_CAST(type,obj))->type
#define DYN_CAST(type,obj)  type##_AUTO_CAST(obj.typeid,obj.letter)

A macro SPM_quotDYN_CAST" efectua a conversão do objecto dentro de um envelope para a sua classe real, i.e., aquela a partir da qual foi criado. Note-se que neste caso a sua expansão resulta numa macro, que se designará por MAC (macro automática de conversão), e cujo nome é construído a partir de um dos argumentos, o tipo, e cuja definição é automaticamente realizada por uma ferramenta que analisa a estrutura de classes. No caso da classe SPM_quotLine" ter-se-ia:

#define LineLetter_AUTO_CAST(ot,obj) (                           \
    _DYN_CAST(ot,LineLetter,obj)                                 \
    (void *)0) /* Error occured: object is of incorrect type */

#define _DYN_CAST(ot,st,obj)                                     \
    LL_TYPEID_CMP(ot,__##st##__TypeName) ? ((st *)obj) :

No caso de uma hierarquia múltipla, as MACs têm em conta a relação entre classes e permitem apenas conversões válidas para as classes em questão, i.e., para objectos da classe actual e das suas subclasses. Existiria uma chamada a SPM_quot_DYN_CAST" por cada uma das conversões possíveis.

Resumindo: o modo genérico de invocar uma carta fica sujeito a duas conversões de tipos, que podem, em algumas circunstâncias ser inúteis. Em qualquer caso, o peso das conversões é pequeno quando comparado com a garantia de suporte à modificações de tipos que um ponteiro para um objecto pode sofrer.



next up previous contents index
Next: Ferramentas Up: O Nível de Previous: Representação de Tipos



David M. M. de Matos
Thu Jun 29 14:58:09 MET DST 1995