ООП. Вопросы применения - страница 8

 
Interesting:

1. Функционал потомков не доступен. Не знаю кто и как, но лично я доступ к SetRadius() и SetSide() из Массива так и не получил.Может там есть путь как проблему решить автогеном, но хочется без этого.

2. Может я с указателями не так работаю, но у меня либо утечка вылазит постоянно либо приходится бить указатели сразу в том блоке где идет основная работа.

Всё доступно... мой пост выше
 
equivalent23:

Можно пример?

Просто приведенный мной пример взят из документации и не понятно как он должен работать..

Вот так работает. Но совершенно не по документации :/ (Зато в очередной раз потренировался на указателях)

#property copyright "Ya"
#property link      "Ya"
#property version   "1.00"
//--- Базовый класс
class CShape
  {
protected:
   int               m_type;                // тип фигуры
   int               m_xpos;                // X - координата точки привязки
   int               m_ypos;                // Y - координата точки привязки
public:
   void           CShape(){m_type=0;};   // конструктор, тип равен нулю
   int            GetType(){return(m_type);};// возвращает тип фигуры
   virtual void           SetRadius(double r){return;};
   virtual void           SetSide(double s){return;};
   virtual double         GetArea(){return(0); }// возвращает площадь фигуры
  };
//--- производный класс Круг
class CCircle: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_radius;              // радиус круга

public:
   void           CCircle(){m_type=1; m_radius=10;};  // конструктор, тип равен 1 
   virtual void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return(3.14*m_radius*m_radius);}// площадь круга
  };
//--- производный класс Квадрат
class CSquare: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_square_side;        // сторона квадрата

public:
   void            CSquare(){m_type=2;}; // конструктор, тип равен 2 
   virtual void            SetSide(double s){m_square_side=s;};
   virtual double GetArea(){return(m_square_side*m_square_side);}//площадь квадрата
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CCircle *ci=new CCircle;
   CSquare *sq=new CSquare;
   CShape  *shapes[2];                       // массив объектов CShape

   shapes[0]=ci;
   shapes[1]=sq;
////---зададим уникальные свойства объектов
   shapes[0].SetRadius(5.0);
   shapes[1].SetSide(4.0);
   for(int i=0; i<2;i++)
     {
      //--- тип и площадь фигуры
      Print("Объект типа "+shapes[i].GetType()+" имеет площадь "+shapes[i].GetArea());
     }
 
AlexSTAL:

Выполняйте:

можно сделать намного проще... виртуализацией:


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

CShape ArrShapes[10]; // массив объектов CShape

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

Ну или я чего-то не понимаю.

Для примера, немного переделанный базовый класс (оформлен как структура)

//class CShape
struct CShape
//Базовый класс
{  
protected: 
int            m_type;                // тип фигуры
int            m_xpos;                // X - координата точки привязки
int            m_ypos;                // Y - координата точки привязки

public:
void           CShape(){m_type=0;};   // конструктор, тип равен нулю
int            GetType(){return(m_type);};// возвращает тип фигуры

void           SetPosX(int s){m_xpos=s;};
int            GetPosX(){return(m_xpos);};

void           SetPosY(int s){m_ypos=s;};
int            GetPosY(){return(m_ypos);};

double GetArea(){return (0); }// возвращает площадь фигуры

};

Если примерно так запихать это все дело в массив доступ к функционалу как минимум объявленному в базовом классе мы получим.

Вопрос в том как получить доступ к функционалу потомком если массив имеет тип базового класса (т.е. массив имеет тип CShape)?

Когда нужно использовать указатели в MQL5
Когда нужно использовать указатели в MQL5
  • 2010.03.25
  • MetaQuotes Software Corp.
  • www.mql5.com
Все объекты в MQL5 по умолчанию передаются по ссылке, но есть возможность использовать и указатели объектов. При этом есть опасность получить в качестве параметра функции указатель неинициализированного объекта. В этом случае работа программы будет завершена критически с последующей выгрузкой. Автоматически создаваемые объекты как правило такой ошибки не вызывают, и в этом отношении они достаточно безопасны. В этой статье мы попробуем разобраться в чем разница между ссылкой и указателей, когда оправдано использование указателей и как написать безопасный код с использованием указателей.
 
Interesting:

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

Вопрос в том как получить доступ к функционалу потомком если массив имеет тип базового класса (т.е. массив имеет тип CShape)?

Я же написал на прошлой странице как:

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base;

void OnStart()
  {
   Base = new CTest;
   Base.m_radius();
   ((CTest *)Base).m_radius();
   delete Base;
  }
 

Тот же самый код, только с массивом:

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   Base[0].m_radius();
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
 
Yedelkin:

Вот так работает. Но совершенно не по документации :/

 

Ну я собственно про тоже, необходимо хотя бы обозначить все функции в базовом классе (иначе к ним доступа не будет).
 
AlexSTAL:

Выполняйте:

Вот за такое:

((CTest *)Base).m_radius();

надо руки отрывать с конфискацией клавиатуры.

В С++ по иерархии классов можно двигаться с помощью dynamic_cast, его и там кстати не любят. В MQL это может стать причиной неявных падений, которые с полутыка не разгребешь, т.к. баг совсем в другом месте.

Поэтому такое приведение категорически не советую использовать. То есть вообще. К предкам пожалуйста, к детям ни ни.

 
TheXpert:

Вот за такое:

надо руки отрывать с конфискацией клавиатуры.

В С++ по иерархии классов можно двигаться с помощью dynamic_cast, его и там кстати не любят. В MQL это может стать причиной неявных падений, которые с полутыка не разгребешь, т.к. баг совсем в другом месте.

Поэтому такое приведение категорически не советую использовать. То есть вообще. К предкам пожалуйста, к детям ни ни.

Как бы помягче то ответить....

Если башка дурная у программиста, то простая операция 1+1 может быть причиной неявных падений....

И хочу заметить, что MQL5 - это не С++...

Это всего лишь возможность, а не вопрос применения....

 
AlexSTAL:

Тот же самый код, только с массивом:


1. Уберите m_radius() из предка, его в примере нет. :) И получите отсутствие работы с ним в OnStart();

2. А можно куда в другое место снести строку delete Base[0]? Скажем если это не скрипт а сова и мне данные в массиве еще пригодятся.

У меня сразу утечка памяти вылазит. Пришлось по этой причине перейти на структуры...

 
Interesting:

1. Уберите m_radius(), его в примере нет. И получите отсутствие работы с ним в OnStart();

2. А можно куда в другое место снести строку delete Base[0]? Скажем если это не скрипт а сова и мне данные в массиве еще пригодятся.

У меня сразу утечка памяти вылазит. Пришлось по этой причине перейти на структуры...

1) Убрал, работает:

class CBase
  {
public:
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
2) Главное удалить до завершения программы... но если у Вас этот указатель создаётся в функции, то нужно позаботиться о его сохранении в глобальном месте...
Причина обращения: