photo
+ Responder ao Tópico
Resultados de 1 a 2 de 2

Thread: Sobrecarga de Operação

  1. #1 Fechar a publicação
    Banned
    Data de afiliação
    Aug 2018
    Postagens
    343
    Obrigado
    91
    Agradecimentos 216 Tempos em 141 Postagens

    Sobrecarga de Operação

    Para facilitar a leitura e escrita de código, a sobrecarga de algumas operações é permitida. O operador de sobrecarga é escrito usando a palavra-chave operator. Os seguintes operadores podem ser sobrecarregados:

    binário +,-,/,*,%,<<,>>,==,!=,<,>,<=,>=,=,+=,-=,/=,*=,%=,&=,|=,^=,<<=,>>=,&&,||,&,|,^
    unário +,-,++,--,!,~
    operador de atribuição =
    operador de indexação []


    Sobrecarga de operação permite o uso da notação de operação (escrita na forma de expressões simples) para objetos complexos - estruturas e classes. Escrevendo expressões usando operações de sobrecarga simplifica a visualização do código fonte, porque uma implementação mais complexa fica escondida.

    Por exemplo, considere números complexos, que consistem de partes real e imaginária. Eles são amplamente utilizados na matemática. A linguagem MQL5 não tem um tipo de dado que represente números complexos, mas é possível criar um novo tipo de dado na forma de uma estrutura ou classe. Declare a estrutura complexa e defina quatro métodos que implementam as quatro operações aritméticas:

    //+------------------------------------------------------------------+
    //| Uma estrutura para operações com números complexos |
    //+------------------------------------------------------------------+
    struct complex
    {
    double re; // Parte real
    double im; // Parte imaginário
    //--- Construtores
    complex():re(0.0),im(0.0) { }
    complex(const double r):re(r),im(0.0) { }
    complex(const double r,const double i):re(r),im(i) { }
    complex(const complex &o):re(o.re),im(o.im) { }
    //--- Operações Aritméticas
    complex Add(const complex &l,const complex &r) const; // Adição
    complex Sub(const complex &l,const complex &r) const; // Subtração
    complex Mul(const complex &l,const complex &r) const; // Multiplicação
    complex Div(const complex &l,const complex &r) const; // Divisão
    };

    Agora, em nosso código nós podemos declarar variáveis representando números complexos, e trabalhar com eles.

    Por exemplo:

    void OnStart()
    {
    //--- Declara e inicialize variáveis de um tipo complexo
    complex a(2,4),b(-4,-2);
    PrintFormat("a=%.2f+i*%.2f, b=%.2f+i*%.2f",a.re,a.im,b.re,b.im);
    //--- Soma dois números
    complex z;
    z=a.Add(a,b);
    PrintFormat("a+b=%.2f+i*%.2f",z.re,z.im);
    //--- Multiplica dois números
    z=a.Mul(a,b);
    PrintFormat("a*b=%.2f+i*%.2f",z.re,z.im);
    //--- Dividir dois números
    z=a.Div(a,b);
    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im);
    //---
    }

    Mas seria mais conveniente usar os operadores usuais "+", "-", "*" e "/" para operações aritméticas comuns com números complexos.

    A palavra-chave operator é usado para definir uma função membro que realiza conversão de tipo. Operações unárias e binárias para variáveis de objeto de classe podem ser sobrecarregadas como funções membro não estáticas. Elas implicitamente agem nos objetos de classe.

    A maioria das operações binárias podem ser sobrecarregadas como funções regulares que tomam uma variável de classe e/ou um ponteiro de objeto desta classe como argumento. Para o nosso tipo complexo, a sobrecarga na declaração se parecerá como:

    //--- Operadores
    complex operator+(const complex &r) const { return(Add(this,r)); }
    complex operator-(const complex &r) const { return(Sub(this,r)); }
    complex operator*(const complex &r) const { return(Mul(this,r)); }
    complex operator/(const complex &r) const { return(Div(this,r)); }

    O exemplo completo do script:

    //+------------------------------------------------------------------+
    //| Programa Script da função start (iniciar) |
    //+------------------------------------------------------------------+
    void OnStart()
    {
    //--- Declara e inicialize variáveis de um tipo complexo
    complex a(2,4),b(-4,-2);
    PrintFormat("a=%.2f+i*%.2f, b=%.2f+i*%.2f",a.re,a.im,b.re,b.im);
    //a.re=5;
    //a.im=1;
    //b.re=-1;
    //b.im=-5;
    //--- Soma dois números
    complex z=a+b;
    PrintFormat("a+b=%.2f+i*%.2f",z.re,z.im);
    //--- Multiplica dois números

    z=a*b;
    PrintFormat("a*b=%.2f+i*%.2f",z.re,z.im);
    //--- Dividir dois números
    z=a/b;
    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im);
    //---
    }
    //+------------------------------------------------------------------+
    //| Uma estrutura para operações com números complexos |
    //+------------------------------------------------------------------+
    struct complex
    {
    double re; // Parte real
    double im; // Parte imaginário
    //--- Construtores
    complex():re(0.0),im(0.0) { }
    complex(const double r):re(r),im(0.0) { }
    complex(const double r,const double i):re(r),im(i) { }
    complex(const complex &o):re(o.re),im(o.im) { }
    //--- Operações Aritméticas
    complex Add(const complex &l,const complex &r) const; // Adição
    complex Sub(const complex &l,const complex &r) const; // Subtração
    complex Mul(const complex &l,const complex &r) const; // Multiplicação
    complex Div(const complex &l,const complex &r) const; // Divisão
    //--- Operadores binárias
    complex operator+(const complex &r) const { return(Add(this,r)); }
    complex operator-(const complex &r) const { return(Sub(this,r)); }
    complex operator*(const complex &r) const { return(Mul(this,r)); }
    complex operator/(const complex &r) const { return(Div(this,r)); }
    };
    //+------------------------------------------------------------------+
    //| Adição |
    //+------------------------------------------------------------------+
    complex complex::Add(const complex &l,const complex &r) const
    {
    complex res;
    //---
    res.re=l.re+r.re;
    res.im=l.im+r.im;
    //--- Resultado
    return res;
    }
    //+------------------------------------------------------------------+
    //| Subtração |
    //+------------------------------------------------------------------+
    complex complex::Sub(const complex &l,const complex &r) const
    {
    complex res;
    //---
    res.re=l.re-r.re;
    res.im=l.im-r.im;
    //--- Resultado
    return res;
    }
    //+------------------------------------------------------------------+
    //| Multiplicação |
    //+------------------------------------------------------------------+
    complex complex::Mul(const complex &l,const complex &r) const
    {
    complex res;
    //---
    res.re=l.re*r.re-l.im*r.im;
    res.im=l.re*r.im+l.im*r.re;
    //--- Resultado
    return res;
    }
    //+------------------------------------------------------------------+
    //| Divisão |
    //+------------------------------------------------------------------+
    complex complex::Div(const complex &l,const complex &r) const
    {
    //--- Numero complexo vazio
    complex res(EMPTY_VALUE,EMPTY_VALUE);
    //--- Verificar se é zero
    if(r.re==0 && r.im==0)
    {
    Print(__FUNCTION__+": número é zero");
    return(res);
    }
    //--- Variáveis auxiliares
    double e;
    double f;
    //--- Selecionando a variante de cálculo
    if(MathAbs(r.im)<MathAbs(r.re))
    {
    e = r.im/r.re;
    f = r.re+r.im*e;
    res.re=(l.re+l.im*e)/f;
    res.im=(l.im-l.re*e)/f;
    }
    else
    {
    e = r.re/r.im;
    f = r.im+r.re*e;
    res.re=(l.im+l.re*e)/f;
    res.im=(-l.re+l.im*e)/f;
    }
    //--- Resultado
    return res;
    }



    A maioria das operações unárias para classes podem ser sobrecarregadas como funções comuns que aceitam um único argumento de objeto de classe ou ponteiro dele. Adicione sobrecarga de operações unárias "-" e "!".

    //+------------------------------------------------------------------+
    //| Uma estrutura para operações com números complexos |
    //+------------------------------------------------------------------+
    struct complex
    {
    double re; // Parte real
    double im; // Parte imaginário
    ...
    //--- Operadores unários
    complex operator-() const; // Unary minus
    bool operator!() const; // Negação
    };
    ...
    //+------------------------------------------------------------------+
    //| Sobrecarregar operador de "menos unário" |
    //+------------------------------------------------------------------+
    complex complex::operator-() const
    {
    complex res;
    //---
    res.re=-re;
    res.im=-im;
    //--- Resultado
    return res;
    }
    //+------------------------------------------------------------------+
    //| Sobrecarregar operador de "negação lógica" |
    //+------------------------------------------------------------------+
    bool complex::operator!() const
    {
    //--- São as partes real e imaginária do número complexo igual a zero?
    return (re!=0 && im!=0);
    }



    Agora nós podemos verificar se valor de um número complexo é zero e obter um valor negativo:

    //+------------------------------------------------------------------+
    //| Programa Script da função start (iniciar) |
    //+------------------------------------------------------------------+
    void OnStart()
    {
    //--- Declara e inicialize variáveis de um tipo complexo
    complex a(2,4),b(-4,-2);
    PrintFormat("a=%.2f+i*%.2f, b=%.2f+i*%.2f",a.re,a.im,b.re,b.im);
    //--- Dividir dois números
    complex z=a/b;
    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im);
    //--- Um número complexo é igual a zero por padrão (no construtor padrão re==0 e im==0
    complex zero;
    Print("!zero=",!zero);
    //--- Atribuir um valor negativo
    zero=-z;
    PrintFormat("z=%.2f+i*%.2f, zero=%.2f+i*%.2f",z.re,z.im, zero.re,zero.im);
    PrintFormat("-zero=%.2f+i*%.2f",-zero.re,-zero.im);
    //--- Verificar se é zero mais uma vez
    Print("!zero=",!zero);
    //---
    }

    Note que nós não tivemos que sobrecarregar o operador de atribuição "=", já que estruturas de tipos simples pode ser diretamente copiadas uma no outra. Assim, nós agora podemos escrever um código para cálculos envolvendo números complexos de maneira usual.

    Sobrecarga de operador de indexação permite obter os valores dos arrays fechados em um objeto, de uma maneira simples e familiar, e isso também contribui para uma melhor legibilidade do código fonte. Por exemplo, nós precisamos fornecer acesso a um símbolo dentro de uma string em uma posição específica. Uma string em MQL5 é um tipo string separado, que não é um array de símbolos, mas com a ajuda de uma operação de indexação sobrecarregada podemos fornecer um trabalho simples e transparente na classe CString gerada:

    Though trading on financial markets involves high risk, it can still generate extra income in case you apply the right approach. By choosing a reliable broker such as InstaForex you get access to the international financial markets and open your way towards financial independence. You can sign up here.


  2. #2 Fechar a publicação
    Banned
    Data de afiliação
    Aug 2018
    Postagens
    343
    Obrigado
    91
    Agradecimentos 216 Tempos em 141 Postagens
    //+----------------------------------------------------------------------+
    //| Uma classe para acessar símbolos em string como na array de símbolos |
    //+----------------------------------------------------------------------+
    class CString
    {
    string m_string;

    public:
    CString(string str=NULL):m_string(str) { }
    ushort operator[] (int x) { return(StringGetCharacter(m_string,x)); }
    };
    //+------------------------------------------------------------------+
    //| Programa Script da função start (iniciar) |
    //+------------------------------------------------------------------+
    void OnStart()
    {
    //--- Um array para receber os símbolos a partir de uma string
    int x[]={ 19,4,18,19,27,14,15,4,17,0,19,14,17,27,26,28,27,5, 14,
    17,27,2,11,0,18,18,27,29,30,19,17,8,13,6 };
    CString str("abcdefghijklmnopqrstuvwxyz[ ]CS");
    string res;
    //--- Fazer um frase usando símbolos da variável str
    for(int i=0,n=ArraySize(x);i<n;i++)
    {
    res+=ShortToString(str[x[i]]);
    }
    //--- Mostrar o resultado
    Print(res);
    }



    Um outro exemplo de sobrecarga do operador de indexação são operações com matrizes. A matriz representa um array dinâmico de duas dimensões, o tamanho do array não é definido com antecedência. Portanto, você não pode declarar um array da forma array[][] sem especificar o tamanho da segunda dimensão, e então passar este array como um parâmetro. Uma possível solução é uma classe especial CMatrix, que contém um array de objetos de classe CRow.

    //+------------------------------------------------------------------+
    //| Programa Script da função start (iniciar) |
    //+------------------------------------------------------------------+
    void OnStart()
    {
    //--- Operações de adição e multiplicação de matrizes
    CMatrix A(3),B(3),C();
    //--- Preparar um array para as linhas
    double a1[3]={1,2,3}, a2[3]={2,3,1}, a3[3]={3,1,2};
    double b1[3]={3,2,1}, b2[3]={1,3,2}, b3[3]={2,1,3};
    //--- Preencher as matrizes
    A[0]=a1; A[1]=a2; A[2]=a3;
    B[0]=b1; B[1]=b2; B[2]=b3;
    //--- Saída de matrizes no log Experts
    Print("---- Os elementos da matriz A");
    Print(A.String());
    Print("---- Os elementos da matriz B");
    Print(B.String());

    //--- Adição de matrizes
    Print("---- Adição das matrizes A e B");
    C=A+B;
    //--- Saída da representação da string formatada
    Print(C.String());

    //--- Multiplicação de matrizes
    Print("---- Multiplicação das matrizes A e B");
    C=A*B;
    Print(C.String());

    //--- Agora mostraremos como obter valores no estilo dos arrays dinâmicos matrix[i][j]
    Print("Saída de valores da matriz C elemento a elemento");
    //--- Atravessar as linhas da matriz - objetos CRow - num loop
    for(int i=0;i<3;i++)
    {
    string com="| ";
    //--- Formar linhas a partir da matriz para o valor
    for(int j=0;j<3;j++)
    {
    //--- Obter o elemento da matriz pelo número de linha e coluna
    double element=C[i][j];// [i] - Acesso para CRow no array m_rows[] ,
    // [j] - Operador sobrecarregado da indexação em CRow
    com=com+StringFormat("a(%d,%d)=%G ; ",i,j,element);
    }
    com+="|";
    //--- Saída dos valores da linha
    Print(com);
    }
    }
    //+------------------------------------------------------------------+
    //| Class "Row" |
    //+------------------------------------------------------------------+
    class CRow
    {
    private:
    double m_array[];
    public:
    //--- Construtores e um destrutor
    CRow(void) { ArrayResize(m_array,0); }
    CRow(const CRow &r) { this=r; }
    CRow(const double &array[]);
    ~CRow(void){};
    //--- Número de elementos na linha
    int Size(void) const { return(ArraySize(m_array));}
    //--- Retorna uma string com valores
    string String(void) const;
    //--- Operador de indexação
    double operator[](int i) const { return(m_array[i]); }
    //--- Operadores de atribuição
    void operator=(const double &array[]); // Uma array
    void operator=(const CRow & r); // Outro objeto CRow
    double operator*(const CRow &o); // Objeto CRow para multiplicação
    };
    //+------------------------------------------------------------------+
    //| Construtor para inicializar uma linha com um array |
    //+------------------------------------------------------------------+
    void CRow::CRow(const double &array[])
    {
    int size=ArraySize(array);
    //--- Se o array não está vazio
    if(size>0)
    {
    ArrayResize(m_array,size);
    //--- Preencher com valores
    for(int i=0;i<size;i++)
    m_array[i]=array[i];
    }
    //---
    }
    //+------------------------------------------------------------------+
    //| Atribuir operação para o array |
    //+------------------------------------------------------------------+
    void CRow::operator=(const double &array[])
    {
    int size=ArraySize(array);
    if(size==0) return;
    //--- Preencher array com valores
    ArrayResize(m_array,size);
    for(int i=0;i<size;i++) m_array[i]=array[i];
    //---
    }
    //+------------------------------------------------------------------+
    //| Operação de atribuição para CRow |
    //+------------------------------------------------------------------+
    void CRow::operator=(const CRow &r)
    {
    int size=r.Size();
    if(size==0) return;
    //--- Preencher array com valores
    ArrayResize(m_array,size);
    for(int i=0;i<size;i++) m_array[i]=r[i];
    //---
    }
    //+------------------------------------------------------------------+
    //| Operador de multiplicação por outra linha |
    //+------------------------------------------------------------------+
    double CRow::operator*(const CRow &o)
    {
    double res=0;
    //--- Verificações
    int size=Size();
    if(size!=o.Size() || size==0)
    {
    Print(__FUNCSIG__,": Falha ao multiplicar duas matrizes, elas são de tamanhos diferentes");
    return(res);
    }
    //--- Multiplicar arrays elemento a elemento e adicionar os produtos
    for(int i=0;i<size;i++)
    res+=m_array[i]*o[i];
    //--- Resultado
    return(res);
    }
    //+------------------------------------------------------------------+
    //| Retorno da representação da string formatada |
    //+------------------------------------------------------------------+
    string CRow::String(void) const
    {
    string out="";
    //--- Se o tamanho do array é maior do que zero
    int size=ArraySize(m_array);
    //--- Trabalhamos apenas com números diferentes de zero dos elementos array
    if(size>0)
    {
    out="{";
    for(int i=0;i<size;i++)
    {
    //--- Recolher os valores para a string
    out+=StringFormat(" %G;",m_array[i]);
    }
    out+=" }";
    }
    //--- Resultado
    return(out);
    }
    //+------------------------------------------------------------------+
    //| Class "Matrix" |
    //+------------------------------------------------------------------+
    class CMatrix
    {
    private:
    CRow m_rows[];

    public:
    //--- Construtores e um destrutor
    CMatrix(void);
    CMatrix(int rows) { ArrayResize(m_rows,rows); }
    ~CMatrix(void){};
    //--- Obter os tamanhos de matriz
    int Rows() const { return(ArraySize(m_rows)); }
    int Cols() const { return(Rows()>0? m_rows[0].Size():0); }
    //--- Retorna o valor da coluna na forma da linha Crow
    CRow GetColumnAsRow(const int col_index) const;
    //--- Retorna uma string com valores de matriz
    string String(void) const;
    //--- O operador de indexação retorna uma string pelo seu número
    CRow *operator[](int i) const { return(GetPointer(m_rows[i])); }
    //--- Operador de adição
    CMatrix operator+(const CMatrix &m);
    //--- Operador de multiplicação
    CMatrix operator*(const CMatrix &m);
    //--- Operador de atribuição
    CMatrix *operator=(const CMatrix &m);
    };
    //+------------------------------------------------------------------+
    //| Um construtor padrão, cria um array de linhas de tamanho zero |
    //+------------------------------------------------------------------+
    CMatrix::CMatrix(void)
    {
    //--- O número zero das linhas na matriz
    ArrayResize(m_rows,0);
    //---
    }
    //+------------------------------------------------------------------+
    //| Retorna o valor da coluna na forma de CRow |
    //+------------------------------------------------------------------+
    CRow CMatrix::GetColumnAsRow(const int col_index) const
    {
    //--- A variável para obter os valores a partir da coluna
    CRow row();
    //--- O número de linhas na matriz
    int rows=Rows();
    //--- Se o número de linhas maior do que zero, executar a operação
    if(rows>0)
    {
    //--- Um array para receber os valores da coluna com índice col_indez
    double array[];
    ArrayResize(array,rows);
    //--- Preenchendo o array
    for(int i=0;i<rows;i++)
    {
    //--- Verificar o número da coluna para a linha i - que podem ultrapassar os limites da matriz
    if(col_index>=this[i].Size())
    {
    Print(__FUNCSIG__,": Erro! Número da coluna ",col_index,"> tamanho da linha ",i);
    break; // linha não inicializará o objeto
    }
    array[i]=this[i][col_index];
    }
    //--- Criar uma linha CRow baseada nos valores do array
    row=array;
    }
    //--- Resultado
    return(row);
    }
    //+------------------------------------------------------------------+
    //| Adicionar duas matrizes |
    //+------------------------------------------------------------------+
    CMatrix CMatrix::operator+(const CMatrix &m)
    {
    //--- O número de linha e colunas na matriz passada
    int cols=m.Cols();
    int rows=m.Rows();
    //--- A matriz recebe os resultados da adição
    CMatrix res(rows);
    //--- Os tamanhos de matriz devem coincidir
    if(cols!=Cols() || rows!=Rows())
    {
    //--- Adição impossível
    Print(__FUNCSIG__,": Falha para adicionar duas matrizes, seus tamanhos são diferentes");
    return(res);
    }
    //--- Array auxiliar
    double arr[];
    ArrayResize(arr,cols);
    //--- Atravessar as linhas para adicionar
    for(int i=0;i<rows;i++)
    {
    //--- Escrever os resultados da adição das strings matriz no array
    for(int k=0;k<cols;k++)
    {
    arr[k]=this[i][k]+m[i][k];
    }
    //--- Colocar o array para a linha matriz
    res[i]=arr;
    }
    //--- retorna o resultado da adição de matrizes
    return(res);
    }
    //+------------------------------------------------------------------+
    //| Multiplicação de duas matrizes |
    //+------------------------------------------------------------------+
    CMatrix CMatrix::operator*(const CMatrix &m)
    {
    //--- Número de colunas da primeira matriz, número de linhas transmitidas na matriz
    int cols1=Cols();
    int rows2=m.Rows();
    int rows1=Rows();
    int cols2=m.Cols();
    //--- Matriz para receber o resultado da adição
    CMatrix res(rows1);
    //--- Matrizes devem ser coordenadas
    if(cols1!=rows2)
    {
    //--- Multiplicação impossível
    Print(__FUNCSIG__,": Falha para multiplicar duas matrizes, formato não é compatível "
    "- o número de colunas no primeiro fator deveria ser igual ao número de linhas na segunda");
    return(res);
    }
    //--- Array auxiliar
    double arr[];
    ArrayResize(arr,cols1);
    //--- Preencher as linhas na multiplicação da matriz
    for(int i=0;i<rows1;i++)// Atravessar as linhas
    {
    //--- Restabelecer o array recebido
    ArrayInitialize(arr,0);
    //--- Atravessar elementos na linha
    for(int k=0;k<cols1;k++)
    {
    //--- Levar valores da coluna k da matriz m para CRow
    CRow column=m.GetColumnAsRow(k);
    //--- Multiplicar duas linhas e escrever o resultado da multiplicação escalar dos vetroes no i-ésimo elemento
    arr[k]=this[i]*column;
    }
    //--- colocar array arr[] na linha i-th da matriz
    res[i]=arr;
    }
    //--- Retornar o produto das duas matrizes
    return(res);
    }
    //+------------------------------------------------------------------+
    //| Operação de atribuição |
    //+------------------------------------------------------------------+
    CMatrix *CMatrix::operator=(const CMatrix &m)
    {
    //--- Preencher e defineir o número de linhas
    int rows=m.Rows();
    ArrayResize(m_rows,rows);
    //--- Preencher nossas linhas com valores das linhas da matriz anterior
    for(int i=0;i<rows;i++) this[i]=m[i];
    //---
    return(GetPointer(this));
    }
    //+------------------------------------------------------------------+
    //| Representação string da matriz |
    //+------------------------------------------------------------------+
    string CMatrix::String(void) const
    {
    string out="";
    int rows=Rows();
    //--- Formar string por string
    for(int i=0;i<rows;i++)
    {
    out=out+this[i].String()+"\r\n";
    }
    //--- Resultado
    return(out);
    }

    Though trading on financial markets involves high risk, it can still generate extra income in case you apply the right approach. By choosing a reliable broker such as InstaForex you get access to the international financial markets and open your way towards financial independence. You can sign up here.


+ Responder ao Tópico

Permissões de postagens

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts