Вопросы по ООП (Объектно Ориентированному Программированию ) - страница 10

 

имена параметров не важны.. разные имена имеют смысл чтобы что-то с чем-то не перепутать..

в декларации функции можно одни значения писать,

public:
   void              SetName(string n);

а самой в функции другие

void CPerson::SetName(string nnn)
  {
   m_name.first_name=GetFirstName(nnn);
   m_name.last_name=GetLastName(nnn);
  }

а можно везде одинаково параметры назвать, это как удобнее кодописатиелю

 

В том же учебнике попался код:

#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Класс-пример с несколькими типами доступа                        |
//+------------------------------------------------------------------+
class CBaseClass
  {
private:             //--- закрытый член недоступен из потомков
   int               m_member;
protected:           //--- защищенный метод доступен из базового класса и его потомков
   int               Member(){return(m_member);}
public:              //--- конструктор класса доступен всем
                     CBaseClass(){m_member=5;return;};
private:             //--- закрытый метод для присвоения значения члену m_member
   void              Member(int value) { m_member=value;};
  };
//+------------------------------------------------------------------+
//| Производный класс с ошибками                                     |
//+------------------------------------------------------------------+
class CDerived: public CBaseClass // public наследование можно не указывать, оно по умолчанию
  {
public:
   void Func() // определим в потомке функцию с обращениями к членам базового класса 
     {
      //--- попытка модификации закрытого члена базового класса
      m_member=0;        // ошибка, закрытый член базового класса никому не доступен
      Member(0);         // ошибка, закрытый метод базового класса не доступен в потомках

Странный момент в конструкторе:

public:              //--- конструктор класса доступен всем
                     CBaseClass(){m_member=5;return;};
Зачем тут оператор return?

Я первый раз встречаю чтобы в конструкторе данный оператор использовался. Ведь по сути конструктор вызывается автоматом. И выход будет по-любому. Смысл в данному операторе в конструкторе разве есть?

 
hoz:

В том же учебнике попался код:

Странный момент в конструкторе:

Зачем тут оператор return?

Я первый раз встречаю чтобы в конструкторе данный оператор использовался. Ведь по сути конструктор вызывается автоматом. И выход будет по-любому. Смысл в данному операторе в конструкторе разве есть?

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

Конструктор и деструктор это обычные функции. Только конструктор по умолчанию и деструктор вызывается автоматом. Остальные пользователь вызывает.

 

В учебнике приводится такой пример применительно к полиморфизму:

//--- Базовый класс
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
   double         GetArea(){return (0); }// возвращает площадь фигуры
  };
//--- производный класс Круг
class CCircle : public CShape            // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double         m_radius;              // радиус круга
public:
   void           CCircle(){m_type=1;};  // конструктор, тип равен 1 
   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 
   void            SetSide(double s){m_square_side=s;};
   virtual double  GetArea(){return (m_square_side*m_square_side);}//площадь квадрата
  };

Я вот одного не понял. Если всё-таки использовать для вызовов объекты дочерник функций т.е. производных методов CCircle и CSquare, то площадь GetArea() можно вычислить минуя объявления в базовом классе. Т.е. в базовом классе не создавать виртуальные функции вообще, а в производных создать обычный метод и всё! Тогда зачем виртуальная функция нужна?

Интересно увидеть адекватный и логичный пример, где видно, что виртуальные функции дают какую-то пользу. Потому что то, что я видел, не логично, по крайне мере, для меня. Хочется понять всё-таки.

 
hoz:

В учебнике приводится такой пример применительно к полиморфизму:

Я вот одного не понял. Если всё-таки использовать для вызовов объекты дочерник функций т.е. производных методов CCircle и CSquare, то площадь GetArea() можно вычислить минуя объявления в базовом классе. Т.е. в базовом классе не создавать виртуальные функции вообще, а в производных создать обычный метод и всё! Тогда зачем виртуальная функция нужна?

Интересно увидеть адекватный и логичный пример, где видно, что виртуальные функции дают какую-то пользу. Потому что то, что я видел, не логично, по крайне мере, для меня. Хочется понять всё-таки.

Это простейший пример для понимания полиморфизма. Чтобы быстро дошло.

Бывают сложные случаи. Когда понадобится, применишь. Сейчас нет смысла заморачиваться. Будет задача, тогда надо думать.

Например, есть у меня базовый класс со всеми возможными интерфейсами чтения/записи. В нём же есть приватные виртуальные методы (всего 2 - чтение/запись), которые связывают этот интерфейс в базовом классе с производными классами. Собственно, призводные классы могут быть любые, где есть работа с файлами (файлы, маппинг, каналы, интернет). Каждый из производных классов определяет по-своему эти виртуальные методы, но у всех классов одинаковый интерфейс из базового класса.

 
hoz:

В учебнике приводится такой пример применительно к полиморфизму:

Я вот одного не понял. Если всё-таки использовать для вызовов объекты дочерник функций т.е. производных методов CCircle и CSquare, то площадь GetArea() можно вычислить минуя объявления в базовом классе. Т.е. в базовом классе не создавать виртуальные функции вообще, а в производных создать обычный метод и всё! Тогда зачем виртуальная функция нужна?

Интересно увидеть адекватный и логичный пример, где видно, что виртуальные функции дают какую-то пользу. Потому что то, что я видел, не логично, по крайне мере, для меня. Хочется понять всё-таки.

Попробую набросать небольшой пример:

#property strict
#property show_inputs

enum Mes_type {
    m1,
    m2
};
input Mes_type mes_t;  // Выберите тип сообщения

class Message {
public:
    virtual void action() {};
};

class Mes1 : public Message {
public:
    virtual void action() {Alert("Типичные ошибки в программах");}
};

class Mes2 : public Message {
public:
    virtual void action() {Alert("Оффлайновые графики");}
};

void OnStart() {
    // Формируем входные данные для какого-то алгоритма
    //////////////////////////////////////////
    Message *mes;                           //
    switch(mes_t)                           //
    {                                       //
        case m1:                            //
            mes = new Mes1;                 //
            break;                          //
        case m2:                            //
            mes = new Mes2;                 //
    }                                       //
    /////////////////////////////////////////
    
    // Рабочий алгоритм
    //////////////////////////////////////////
    mes.action();                           //
    //////////////////////////////////////////
  
    delete mes;
}

Благодаря такой структуре, при возможных дальнейших доработках, нам не нужно лезть в рабочий алгоритм, который может быть очень большим и сложным (здесь все упрощено), нужно будет лишь добавить еще одного наследника, m3 в перечислении и ещё один case в switch. Т.е. мы унифицировали входные данные что позволит избежать правки в главной части программы.

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

 
hoz:

В учебнике приводится такой пример применительно к полиморфизму:

Я вот одного не понял. Если всё-таки использовать для вызовов объекты дочерник функций т.е. производных методов CCircle и CSquare, то площадь GetArea() можно вычислить минуя объявления в базовом классе. Т.е. в базовом классе не создавать виртуальные функции вообще, а в производных создать обычный метод и всё! Тогда зачем виртуальная функция нужна?

Интересно увидеть адекватный и логичный пример, где видно, что виртуальные функции дают какую-то пользу. Потому что то, что я видел, не логично, по крайне мере, для меня. Хочется понять всё-таки.

Вот простой пример:

CShape* GetNewShape()
{
        if( ... ) // Здесь какое-то условие.
                return new CCircle();
        else
                return new CSquare();
}

CShape* M[10];

for( int i = 0; i < 10; i++ )
{
        M[i] = GetNewShape();
}


double WholeArea = 0.0;
for( int i = 0; i < 10; i++ )
{
        WholeArea += M[i].GetArea();
}
Мы используем функцию GetArea(), не зная, для какой фигуры она вызывается.
 

У меня есть вот такой вот Сеттер в классе:

//---- SetColorBySend
TradingFunc::SetColorBySend (const color fc_ColorSendBuy,      // Цвет открытия ордера на покупку
                             const color fc_ColorSendSell)     // Цвет открытия ордера на продажу
{
   ColorBySend [2] = {fc_ColorSendBuy, fc_ColorSendSell};
}

Компилятор ругается в общем-то на такое присвоение элементов массиву ColorBySend так:

'fc_ColorSendBuy' - constant expression required        TradingFunc.mqh 91      23
'fc_ColorSendSell' - constant expression required       TradingFunc.mqh 91      40
'{' - expression expected       TradingFunc.mqh 91      22
С чем это связано? Неужели нужно поэлементно присваивать значения? Списком не возможно? С чем это связано? Ведь так даже в учебнике присваивание происходит...
 
hoz:

У меня есть вот такой вот Сеттер в классе:

Компилятор ругается в общем-то на такое присвоение элементов массиву ColorBySend так:

С чем это связано? Неужели нужно поэлементно присваивать значения? Списком не возможно? С чем это связано? Ведь так даже в учебнике присваивание происходит...

 

Конструкция вида {что-то, что-то еще} может быть только массивом констант. У вас же туда подставлены переданные в функцию параметры, которые по сути - локальные переменные функции. Модификатор const в данном случае не имеет значения, так как он только указывает на невозможность можификации переданной величины. В итоге
{fc_ColorSendBuy, fc_ColorSendSell}
- это переменное выражение, которое компильятор не может понять. Увы.
 
Инициализация списком возможна только при объявлении.
Причина обращения: