Вопрос по указателям

 

Я прошерстил тему указателей, и, в принципе мне стало понятно как ими пользоваться и зачем они нужны в теории, но, т.к. я работал больше с языками, где есть гарбэдж коолекторы т.к. виртуальная машина сами высвобождает память при необходиомсти и в нужный момент, то есть некоторые вопросы. Вот, например, я открыл код эксперта ExpertMACD, который идёт в базовой поставке в платформой и решил поглядеть как там написан код, больше для того, что бы увидеть как работать с указателями. И я увидел эти моменты. Вот например:

   CExpertTrade     *m_trade;                    // trading object

Вызывается метод из класса

bool CExpert::OpenLong(double price,double sl,double tp)
  {
   if(price==EMPTY_VALUE)
      return(false);
//--- get lot for open
   double lot=LotOpenLong(price,sl);
//--- check lot for open
   lot=LotCheck(lot,price,ORDER_TYPE_BUY);
   if(lot==0.0)
      return(false);
//---
   return(m_trade.Buy(lot,price,sl,tp));
  }

Я так понимаю вызывать методы из класса можно только по ссылке на адресс класса т.е. из указателя на класс? Меня смущает то, что в Java или  С# это можно сделать проще... Вызвать из объекта т.е. экземпляра класса. Там было бы вот так:

CExpertTrade m_trade = new CExpertTrade();                    // trading object
m_trade.BUY();

Такой вариант получается в С++ и в МКЛ соответственно не прокатывает?

 

Ты путаешь понятия класс и экземпляр класса.

В твоем случае - ты создаешь два объекта CExpertTrade - один на стеке, другой по new, приравниваешь указатель одного к другому (теряешь один из объектов), а затем вызываешь функцию покупки у класса, а не у объекта. Это ошибка - функции можно вызывать только у объектов. Исключение - статические функции, но и они вызываются другим синтаксисом (через двойное двоеточие)

Правильно будет так:

// Объявляем указатель, создаем объект, и приравниваем полученный указатель объявленнному.
CExpertTrade m_trade* = new CExpertTrade();  

// Вызываем у созданного объекта (по указателю) функцию покупки.
m_trade.BUY(); 
 
George Merts:

Ты путаешь понятия класс и экземпляр класса.

Не путаю. Просто думал об указателе и описался)) Я выше поправил то, что думаю.


George Merts:

В твоем случае - ты создаешь два объекта CExpertTrade - один на стеке, другой по new, приравниваешь указатель одного к другому (теряешь один из объектов), а затем вызываешь функцию покупки у класса, а не у объекта. Это ошибка - функции можно вызывать только у объектов. Исключение - статические функции, но и они вызываются другим синтаксисом (через двойное двоеточие)

Ну так если функции можно вызвать только у объектов, то почему в моём случае функция вызывается не из объекта? Ведь функция Buy() не является статичной. Вот она:

bool CTrade::Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment="")
  {
   CSymbolInfo sym;
//--- check volume
   if(volume<=0.0)
     {
      m_result.retcode=TRADE_RETCODE_INVALID_VOLUME;
      return(false);
     }
//--- check symbol
   sym.Name((symbol==NULL)?Symbol():symbol);
//--- check price
   if(price==0.0)
     {
      sym.RefreshRates();
      price=sym.Ask();
     }
//---
   return(PositionOpen(sym.Name(),ORDER_TYPE_BUY,volume,price,sl,tp,comment));
  }
 

Структуры, классы и интерфейсы

Даже говорить не о чем.

 
Konstantin Nikitin:

Структуры, классы и интерфейсы

Даже говорить не о чем.

Ну вот смотрите. В первом после я показал как вызывается метод Buy. Причём экземпляр через new не создавался. А пройдя по ссылке я вижу, что:

// CFoo foo; // такой вариант использовать нельзя - конструктор по умолчанию не задан 
//--- допустимые варианты создания объекта CFoo 
   CFoo foo1(TimeCurrent());     // явный вызов параметрического конструктора 
   CFoo foo2();                  // явный вызов параметрического конструктора с параметром по умолчанию 
   CFoo foo3=D'2009.09.09';      // неявный вызов параметрического конструктора 
   CFoo foo40(foo1);             // явный вызов конструктора копирования 
   CFoo foo41=foo1;              // неявный вызов конструктора копирования 
   CFoo foo5;                    // явный вызов конструктора по умолчанию (если конструктор по умолчанию отсутствует, 
                                 // то вызывается параметрический конструктор с параметром по умолчанию) 
//--- допустимые варианты получения указателей CFoo 
   CFoo *pfoo6=new CFoo();       // динамическое создание объекта и получение указателя на него 
   CFoo *pfoo7=new CFoo(TimeCurrent());// ещё один вариант динамического создания объекта 
   CFoo *pfoo8=GetPointer(foo1); // теперь pfoo8 указывает на объект foo1 
   CFoo *pfoo9=pfoo7;            // pfoo9 и pfoo7 указывают на один и тот же объект 
   // CFoo foo_array[3];         // такой вариант использовать нельзя - конструктор по умолчанию не задан 

Такого варианта я не увидел в справке. Опять же возникл вопрос, как вызывалась функция (метод) из  не объекта, в случает, если этот объект не статический. Если бы метод был статический, я бы не спрашивал. А в этом случает не всё однозначно..

 
hoz:

Ну вот смотрите. В первом после я показал как вызывается метод Buy. Причём экземпляр через new не создавался. А пройдя по ссылке я вижу, что:

Такого варианта я не увидел в справке. Опять же возникл вопрос, как вызывалась функция (метод) из  не объекта, в случает, если этот объект не статический. Если бы метод был статический, я бы не спрашивал. А в этом случает не всё однозначно..

Выбирайте

#include <Expert\ExpertTrade.mqh>
CExpertTrade m_trade;

void fun()
{
    m_trade.Buy(...);
}
#include <Expert\ExpertTrade.mqh>

class CMyClass
{
private:
   CExpertTrade *m_trade;
   void fun()
   {
      m_trade.Buy(...);
   };
public:
   CMyClass()
   {
      m_trade = new CExpertTrade;
   };
   ~CMyClass()
   {
      if(m_trade) delete m_trade;
   };
};
#include <Expert\ExpertTrade.mqh>

class CMyClass : public CExpertTrade
{
private:
   void fun()
   {
      Buy(...);
   };
public:
   CMyClass(){};
   ~CMyClass(){};
};
 

Я так понимаю, если не нужно использовать именно свойства самого объекта, а лишь пользоваться функциями, то можно пользоваться указателями и не создавать объекты через new. Я верно понимаю? Вчера почитал статьи здесь и понял, что имелось ввиду что-то в этом плане.

Кстати, вот по этому коду вопрос:

#include <Expert\ExpertTrade.mqh>

class CMyClass
{
private:
   CExpertTrade *m_trade;
   void fun()
   {
      m_trade.Buy(...);
   };
public:
   CMyClass()
   {
      m_trade = new CExpertTrade;
   };
   ~CMyClass()
   {
      if(m_trade) delete m_trade;
   };
};

Как вообще может такое писаться?

if(m_trade) delete m_trade;

Ведь m_trade это не булевая переменная, а указатель.. Как это условие вообще исполняется?

 
hoz:

Я так понимаю, если не нужно использовать именно свойства самого объекта, а лишь пользоваться функциями, то можно пользоваться указателями и не создавать объекты через new. Я верно понимаю? Вчера почитал статьи здесь и понял, что имелось ввиду что-то в этом плане.

Кстати, вот по этому коду вопрос:

Как вообще может такое писаться?

Ведь m_trade это не булевая переменная, а указатель.. Как это условие вообще исполняется?

Так обратите внимание на это

m_trade = new CExpertTrade;

А писаться такое может по простой причине. Прежде чем удалять объект ни когда не помешает проверить, а есть ли он вообще и не был ли удален ранее.

Можно и так разыграть

#include <Expert\ExpertTrade.mqh>
CExpertTrade *m_trade;

void fun()
{
    m_trade = new CExpertTrade;
    m_trade.Buy(...);
    delete m_trade;
}

Я вам давал выше ссылку. Буковок много, но прочитать думаю все-же можно.

 
Konstantin Nikitin:

Так обратите внимание на это

А писаться такое может по простой причине. Прежде чем удалять объект ни когда не помешает проверить, а есть ли он вообще и не был ли удален ранее.

Можно и так разыграть

Я вам давал выше ссылку. Буковок много, но прочитать думаю все-же можно.

Так я по вашей ссылке прочёл всё. Остались некоторые моменты, которые не сразу уложились в голове, и я их паралельно проверяю в тестовом варианте.

По сути, то что нужно проверять указатель это понятно. Но более логично проверить будет в вашем случае вот так:

#include <Expert\ExpertTrade.mqh>
CExpertTrade *m_trade;

void fun()
{
  m_trade = new CExpertTrade;
  if (CheckPointer(m_trade) == POINTER_INVALID)
    Print(__FUNCTION__," переменная 'obect' не инициализирована!");
  delete m_trade;
}

А вот такое:

if(m_trade) delete m_trade;

На первый взгляд не читабельно т.к. я привык пользоваться такими проверками сугубо для булевых переменных..