Projeto do assessor - página 5

 

George Merts
Стандартный CObject - это "объект списка или сортированного массива". CMyObject - это CObject, имеющий определенный тип, и содержащий некоторое значение, данное при его создании. Этот объект мне понадобился всвязи с повсеместным приведением объектов к базовому абстрактному классу - чтобы понимать по указателю, на какой именно объект "на самом деле" указывает. Тип CMyObject - устанавливается как раз той самой функцией SetMyObjectType(). Эта функция в обязательном порядке вызывается в конструкторах любых наследников от CMyObject, чтобы назначить идентификатор класса, к которому принадлежит создаваемый объект.

Seu construtor é aberto e não parametrizado:

class CTradeHistoryI: public CMyObject
{
public:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

Isto significa que um herdeiro pode ou não definir seu próprio tipo. Portanto, se você se esquecer de chamar o método SetMyObjectType dentro do descendente, você está ferrado.

O que você pode fazer?

1. Deve-se fechar o construtor de fora da criação:

class CTradeHistoryI: public CMyObject
{
protected:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

Neste caso somente o descendente CTradeHistoryI será capaz de criar uma instância, o que significa que não haverá necessidade do tipo MOT_TRADE_HISTORY_I. Note que o tipo MOT_TRADE_HISTORY_I nunca existe na realidade, porque o CTradeHistoryI é uma interface, e não pode haver nenhuma instância deste tipo. Isto é, fechando o construtor resolvemos a contradição - descrição do tipo que não existe.

2. Vamos definir o requisito explícito de digitação no momento da criação da instância:

enum ENUM_OBJ_TYPE
{
   OBJ_HIST_DEALS_LIST,
   OBJ_HIST_ORDERS_LIST
   ...
};

class CTradeHistoryI: public CMyObject
{
private:
   ENUM_OBJ_TYPE   m_obj_type;
protected:
   CTradeHistoryI(ENUM_OBJ_TYPE obj_type)
   {
      m_obj_type = obj_type;
   }
public:
   ENUM_OBJ_TYPE ObjectType(void) const
   {
      return m_obj_type;
   }
};

class CTradeHistory : public CTradeHistoryI
{
public:
   CTradeHistory(void);
};

CTradeHistory::CTradeHistory(void) : CTradeHistory(OBJ_HIST_DEALS_LIST)
{
}

É isso, agora nenhum descendente pode se criar sem uma especificação explícita do tipo.

 
Vasiliy Sokolov:

Por que reinventar a roda na forma de CMyObject, quando existe um CObject padrão que todos entendem?

Não sei que bem você encontrou em MQL CObject. Dois ponteiros desnecessários enfiados em cada objeto = 16 bytes perdidos + overhead desnecessário na alocação de memória e inicialização destes ponteiros. O OOP em si diminui o desempenho e se você acrescentar tais soluções inúteis...
 
Alexey Navoykov:
Não sei o bem que você encontrou no CObjeto da MQL. Dois ponteiros desnecessários amontoados em cada objeto = 16 bytes desperdiçados + overhead desnecessário na alocação de memória e inicialização destes ponteiros. O OOP em si diminui o desempenho e se você acrescentar tais soluções inúteis...

Aprenda OOP primeiro, depois discutiremos isso. A inicialização do m_prev, m_next não acontece no caso geral.

 
Vasiliy Sokolov:

Aprenda OOP primeiro, depois discutiremos isso. A inicialização do m_prev, m_next em geral não acontece se alguma coisa acontecer.

Somente depois de você.

E assim, por uma questão de informação, a inicialização de indicadores na MQL é sempre realizada.

 
Vasiliy Sokolov:

Seu construtor é aberto e não parametrizado:

Isto significa que um herdeiro pode ou não definir seu próprio tipo. Portanto, se você se esquecer de chamar o método SetMyObjectType dentro do descendente, você está ferrado.

O que você pode fazer?

...

Sim, de fato em alguns casos eu esqueço de especificar SetMyObjectType() - e os objetos são criados com o tipo CMyObject por padrão.

E o método de solução é um bom método.

As sugestões são aceitas.

Mas não gosto do construtor protegido.

 
George Merts:

Sim, de fato, em alguns casos eu esqueço de especificar SetMyObjectType() - e os objetos são criados com o tipo CMyObject por padrão.

E o método de solução é um bom método.

Sugestões aceitas.

Embora eu não goste de construtor de proteção.

Construtor protegido complica a vida somente para aquelas classes que são herdadas diretamente dos pais com tal construtor. Mas no nível do usuário, você pode criar objetos derivados sem hesitação e livremente.

Portanto, o inconveniente não deve ser observado.

E não há outras opções na MQL, porque não há um sistema de verificação de tipo, ou melhor, ele existe, mas de uma forma subdesenvolvida, portanto, temos que proteger o tipo escondendo um construtor.

 
Alexey Navoykov:
Não sei que bem você encontrou no CObjeto da MQL. Dois ponteiros desnecessários enfiados em cada objeto = 16 bytes perdidos + overhead desnecessário na alocação de memória e inicialização destes ponteiros. O OOP por si só retarda o desempenho e quando se lhe acrescentam soluções tão inúteis...

Por que "inútil"? As despesas gerais são, em minha opinião, muito pequenas, e obviamente vale a conveniência que a CObject dá ao organizar listas e matrizes ordenadas.

Se precisamos perseguir microssegundos e bytes, então é claro, faz sentido pensar se esses mesmos "bytes perdidos" não são responsáveis por muitos recursos. Mas como minha prática demonstra, a conveniência da escrita e manutenção de códigos é muito mais importante.

A propósito, eu estive recentemente envolvido na otimização de códigos - meus Conselheiros Especialistas foram, de alguma forma, muito lentos no testador. A função mais lenta foi na atualização de dados. Por isso, tentei diminuir o apelo a esta atualização em todos os sentidos. Mas, recentemente tornou-se possível fazer o perfil do código no testador. E para minha grande surpresa, vi que a maior parte do tempo do meu Conselheiro Especialista é gasto na função de pedir o estado terminal (que eu não precisava (quase)) (era feito a cada atualização, e era simplesmente feito "ao mesmo tempo" com o resto). E acima de tudo - desperdiçado na função de solicitar a memória livre. Pequena mudança no código, de modo que o estado do terminal é consultado apenas uma vez na inicialização e depois nas atualizações - apenas quando explicitamente apontado - acelerou os testes em mais de três vezes!

Assim, as "despesas gerais desnecessárias" podem não se perder de forma alguma onde estamos procurando.

 
George Merts:

Portanto, as "despesas gerais desnecessárias" podem não se perder de forma alguma onde estamos procurando.

Não discuta com ele. Seu único objetivo é berrar. Você nunca provará nada a pessoas como ele. A melhor estratégia para lidar com tais personagens é ignorar totalmente.
 
George Merts:

Por que "inútil"? As despesas gerais são, em minha opinião, muito pequenas, e vale claramente a conveniência que a CObject proporciona na organização de listas e matrizes ordenadas.

Estas "conveniências" são implementadas por cima. Que tipo de lista muda algo em seus objetos? Em essência, acontece que não se pode colocar objetos constantes em uma lista. Ou imagine seu objeto em tal lista, você o envia para uma função, que também o coloca em sua lista, e então você recebe seu objeto de volta com as alterações anteriores e seguintes, e o jogo começa ...

No mundo civilizado as listas são implementadas através de objetos auxiliares do Nodo, que armazenam as indicações necessárias. E tocar nos próprios objetos do usuário é um disparate. Portanto, não se trata apenas das despesas gerais, mas da incorreção fundamental de tudo isso. Os desenvolvedores acabaram de remendar algo rapidamente, e você está feliz como se devesse ser assim.

 
Alexey Navoykov:

Estas 'conveniências' são implementadas através de um único lugar. Que tipo de lista é que muda algo em seus objetos? Em essência, não se pode colocar objetos constantes em uma lista. Ou imagine a situação, quando você envia seu objeto em tal lista para uma função, que também o coloca em sua lista, e então você recebe seu objeto de volta com as alterações anteriores e seguintes, e o jogo começa ...

No mundo civilizado as listas são implementadas através de objetos auxiliares do Nodo, que armazenam as indicações necessárias. E tocar nos próprios objetos do usuário é um disparate. Portanto, não se trata apenas das despesas gerais, mas da incorreção fundamental de tudo isso. Os desenvolvedores apenas empedraram algo a curto prazo e você está feliz como se tivesse que ser assim.

Bem, sim, você não pode colocar objetos constantes em uma lista.

Entretanto, eu uso constantemente a funcionalidade CObject e nenhum dos meus críticos sugeriu nada semelhante a objetos de arrays e listas da Biblioteca Padrão.

"A maneira como as coisas devem ser feitas" é a gritaria de todos. Mas para sugerir algo, de repente, não há nada.

Mesmo aqueles participantes que realmente oferecem soluções de software diferentes, não oferecem um substituto para o CObject - na maioria das vezes não o utilizam de forma alguma, menos frequentemente utilizam sua funcionalidade, não prestando atenção à "implementação em um só lugar", o que significa que a implementação é bastante boa.

Se fosse ruim, eles já teriam oferecido um substituto há muito tempo.

Razão: