Sobrecarga de Operadores

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (1)

Veja neste artigo de Rodolfo de Faria, o recurso de sobrecarga de operadores, adicionada ao Delphi para compatibilidade com o .NET Framework.

Simplifique expressões usando este recurso

Rodolfo de Faria

Sobrecarga de operadores (operator overloading) é um dos inúmeros recursos adicionados ao Delphi para compatibilidade com o .NET Framework. No Delphi 2005 penas a personalidade .NET dispõe desse recurso. No Delphi 2006 temos sobrecarga de operadores também para Win32. Veja neste artigo alguns exemplos de uso e dicas de como implementá-lo.

O que é e para que serve?

A sobrecarga de operadores permite que a linguagem seja estendida e que você possa fazer somas, multiplicações, conversões e várias outras operações entre os objetos que você criou. Imagine que você tenha uma classe que faça soma de matrizes, como mostrado na Listagem 1. Observe como o código fica mais legível.

 

Listagem 1. Código mais legível com o uso de sobrecarga de operadores

var

  a, b, c, x: TMatriz;

  ...

  { Sem operator overloading }

  x = a.Soma(b.Soma(c));

  { Com operator overloading }

  x = a + b + c;

 

Para cada operador que se deseja sobrecarregar é necessário criar um método de classe com uma assinatura específica. Veja na Tabela 1 alguns tipos de operadores existentes e como os métodos devem ser declarados.

 

Tipo

Operadores

Assinatura

Exemplo de uso

Conversão

typecast implícito typecast explícito

Implicit(b: TBugalho): TAlho

Explicit(b: TBugalho): TAlho

Alho := bugalho

Alho := TAlho(bugalho)

Unário

-

+

Inc

Negative(c: TComplexo): TComplexo

Positive(c: TComplexo): TComplexo

Inc(m: TMatriz): TMatriz

complexo1 := -complexo2

complexo1 := +complexo2

Inc(matriz1)

Comparação

=

Equal(c1,c2: TComplexo): boolean

GreaterThan(c1,c2: TComplexo): boolean

LessThan(c1,c2: TComplexo): boolean

If c1 = c2 then

If c1 > c2 then

If c1 < c2 then

Binário

/

div

+

-

Divide(c1,c2: TComplexo): TComplexo

IntDivide(c1,c2: TComplexo): TComplexo

Add(c1,c2: TComplexo): TComplexo

Subtract(c1,c2: TComplexo): TComplexo

Result:=c1 / c2

Result:=c1 div c2

Result:=c1 + c2

Result:=c1 – c2

Tabela 1. Apenas alguns operadores que podem ser sobrecarregados

Para exemplificar usei a classe TComplexo (para simbolizar um número complexo, aquele que tem uma parte real e outra imaginária), mas qualquer tipo de objeto ou record pode ser colocado nas assinaturas acima. Em Delphi os operadores são declarados por extenso. Os métodos não podem ser chamados diretamente como métodos comuns, somente na forma de operadores, ou seja, você não pode fazer, por exemplo, o seguinte código:

 

Result := TMinhaClasse.IntDivide(n1, n2);

        

Para uma lista completa dos operadores que podem ser sobrecarregados consulte no Help o tópico Delphi 2005 Concepts - Operator Overloads (.NET).

Exemplo 1

Vamos criar uma classe chamada “TLutador”, criar alguns lutadores e sobrecarregar os operadores “>” e “<” . Crie uma aplicação Windows Forms, adicione uma unit e digite o código da Listagem 2.

 

Listagem 2. Unit Lutadores

unit ClubeDelphi.Exemplos.OperatorOverloading.Lutadores;

 

interface

 

type

  TLutador = class

  private

    FForca, FInteligencia, FResistencia: integer;

  protected

    function Pontuacao: integer;

  public

    property Forca: integer read FForca write FForca;

    property Inteligencia: integer read FInteligencia

      write FInteligencia;

    property Resistencia: integer read FResistencia

      write FResistencia;

 

    class operator GreaterThan(

      const a, b: TLutador): boolean;

    class operator LessThan(a, b: TLutador): boolean;

  end;

 

implementation

 

class operator TLutador.GreaterThan(

  const a, b: TLutador): boolean;

begin

  Result := a.Pontuacao > b.Pontuacao;

end;

 

class operator TLutador.LessThan(

  a, b: TLutador): boolean;

begin

  Result := a.Pontuacao < b.Pontuacao;

end;

 

function TLutador.Pontuacao: integer;

begin

  Result := FForca*3 + FInteligencia + FResistencia*2;

end;

end.

 

No formulário principal adicione um botão e no evento Click adicione o código da Listagem 3.

 

Listagem 3. Confrontando Ken e Ryu, dois ícones do jogo Street Fighter

procedure TWinForm1.Button1_Click(

  sender: System.Object; e: System.EventArgs);

var

  Ryu,Ken: TLutador;

begin

  { Declare Lutadores na uses }

  Ryu := TLutador.Create;

  Ryu.Forca := 9;

  Ryu.Inteligencia := 8;

  Ryu.Resistencia := 8;

 

  Ken := TLutador.Create;

  Ken.Forca := 9;

  Ken.Inteligencia := 9;

  Ken.Resistencia := 7;

  { Na linha abaixo o método GreaterThan

    está sendo invocado }

  if Ken > Ryu then

    MessageBox.Show('Ken!')

  { Aqui LessThan está sendo invocado }

  else if Ken < Ryu then  

    MessageBox.Show('Ryu!')

  else

    MessageBox.Show('Empate!');

end;

Exemplo 2

Vamos criar duas classes de matrizes, uma com sobrecarga de operadores e outra sem. Para simplificar, nossa matriz terá dimensões 2 x 2 e seu construtor a preencherá automaticamente. As duas classes serão descendentes de TMatriz.  Crie outra unit e digite o código da Listagem 4.

 

Listagem 4. Comparação entre duas classes de matrizes

unit ClubeDelphi.Exemplos.OperatorOverloading.Matrizes;

 

interface

 

type

  TMatriz = class

  public

    Numeros: array[1..2, 1..2] of integer;

    constructor Create(n: integer = 0);

  end;

 

  TMatrizAntiga = class(TMatriz)

    function Soma(m:TMatrizAntiga): TMatrizAntiga;

    function FormataString: string;

  end;

 

  TMatrizNova = class(TMatriz)

  public

    class operator Add(

      m1, m2: TMatrizNova): TMatrizNova;

    class operator Implicit(m: TMatrizNova): string;

  end;

 

implementation

 

{ TMatriz }

constructor TMatriz.Create(n: integer);

begin

  inherited Create;

  Numeros[1,1] := n;

  Numeros[1,2] := n;

  Numeros[2,1] := n;

  Numeros[2,2] := n;

end;

 

{TMatrizAntiga}

function TMatrizAntiga.FormataString: string;

begin

  Result := Numeros[1,1].ToString + ' ' +

    Numeros[1,2].ToString + #13 +

    Numeros[2,1].ToString + ' ' +

    Numeros[2,2].ToString;

end;

 

function TMatrizAntiga.Soma(

  m: TMatrizAntiga): TMatrizAntiga;

var

  l, c: integer;

begin

  Result := TMatrizAntiga.Create;

  for l := 1 to 2 do

    for c := 1 to 2 do

      Result.Numeros[l, c] :=

        Numeros[l, c] + m.Numeros[l, c];

end;

 

{ TMatrizNova }

class operator TMatrizNova.Add(

  m1, m2: TMatrizNova): TMatrizNova;

var

  l,c: integer;

begin

  Result := TMatrizNova.Create;

  for l := 1 to 2 do

    for c:=1 to 2 do

      Result.Numeros[l, c] :=

        m1.Numeros[l, c] + m2.Numeros[l, c];

end;

 

class operator TMatrizNova.Implicit(

  m: TMatrizNova): string;

begin

  Result := m.Numeros[1,1].ToString + ' ' +

    m.Numeros[1,2].ToString + #13 +

    m.Numeros[2,1].ToString + ' ' +

    m.Numeros[2,2].ToString;

end;

end.

 

No formulário principal adicione dois botões e em seus eventos Click adicione o código da Listagem 5.

 

Listagem 5. Testando o código

{ Declare Matrizes na uses }

procedure TWinForm1.Button2_Click(

  sender: System.Object; e: System.EventArgs);

var

  m1,m2,m3,temp: TMatrizAntiga;

begin

  m1 := TMatrizAntiga.Create(1);

  m2 := TMatrizAntiga.Create(2);

  m3 := TMatrizAntiga.Create(3);

  temp := m1.Soma(m2.Soma(m3));

  MessageBox.Show(temp.FormataString);

end;

 

procedure TWinForm1.Button3_Click(

  sender: System.Object; e: System.EventArgs);

var

  m1,m2,m3: TMatrizNova;

begin

  m1 := TMatrizNova.Create(1);

  m2 := TMatrizNova.Create(2);

  m3 := TMatrizNova.Create(3);

  { Aqui o método Add é chamado duas vezes e o método

    Implicit chamado uma vez }

  MessageBox.Show(m1 + m2 + m3);

end;

 

Ambas as soluções exibem o mesmo resultado. Veja que efetuamos duas somas e uma conversão implícita para string, tudo em apenas uma linha e sem comprometer a legibilidade do código.

Cuidados a serem tomados

·         Não altere comportamentos default para evitar confusão. Numa expressão binária, como por exemplo, a = b + c, os objetos b e c não devem ter seus valores alterados.

·         Implemente a sobrecarga de operadores se essa vai ajudar ou simplificar o uso da classe. Se o uso não é intuitivo, a sobrecarga pode ter sido mal aplicada.

Conclusões

  Tudo que se faz com operator overload pode-se fazer com chamadas a métodos ou funções. Usuários das versões anteriores do Delphi (6 e 7) podem obter um efeito semelhante usando Custom Variants. Para mais informações dê uma olhada nos links fornecidos.

 

Links

www.freepascal.org/docs-html/ref/refch11.html#x134-14100011

Tutorial sobre operator overloading usando Free Pascal

www.parashift.com/c++-faq-lite/operator-overloading.html

Apresenta uma lista de boas práticas ao usar operator overloading

tinyurl.com/cl44o

Documentação da Microsoft sobre operator overloading

 

Rodolfo de Faria (rodolfo_faria@ig.com.br) é Analista de Sistemas e desenvolve em Delphi há 5 anos. Responde pela área de informática da empresa Hércules Sistemas Logísticos em Caçapava – SP. Nas horas vagas leciona Delphi e é colaborador do sistema Rau-Tu da Unicamp (www.rau-tu.unicamp.br)

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?