Questions on OOP (Object Oriented Programming) - page 10

 

parameter names are not important... different names make sense so that something is not confused with something...

You can write some values in the function declaration,

public:
   void              SetName(string n);

and other values in the function itself

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

or you can name the parameters identically everywhere, whichever is more convenient for the code-writer

 

In the same textbook, the code came across:

#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);         // ошибка, закрытый метод базового класса не доступен в потомках

Strange thing about the constructor:

public:              //--- конструктор класса доступен всем
                     CBaseClass(){m_member=5;return;};
Why is there a return operator here?

This is the first time I've seen this operator used in the constructor. In fact, the constructor is called automatically. And there will be an output anyway. Does this operator make sense in the constructor?

 
hoz:

In the same textbook, the code came across:

Strange thing about the constructor:

Why is there a return operator here?

This is the first time I've seen this operator used in the constructor. In fact, the constructor is called automatically. And there will be an output anyway. Does this operator make sense in the constructor?

It is not needed in this example, but there can be complex initialization when early exit is needed.

The constructor and destructor are normal functions. Only the default constructor and destructor are called automatically. The others are called by the user.

 

The textbook gives this example in relation to polymorphism:

//--- Базовый класс
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);}//площадь квадрата
  };

There's one thing I don't understand. If we use child function objects for calls, i.e. derived methods CCircle and CSquare, then GetArea() area can be calculated bypassing declarations in base class. I.e. do not create virtual functions in base class at all, and in derived methods create a simple method and that's it! So why do we need a virtual function?

It's interesting to see an adequate and logical example, where you can see that virtual functions provide some benefit. Because what I saw was not logical, at least for me. I would like to understand it all the same.

 
hoz:

The textbook gives this example in relation to polymorphism:

There's one thing I don't understand. If we use child function objects for calls, i.e. derived methods CCircle and CSquare, then GetArea() area can be calculated bypassing declarations in base class. I.e. do not create virtual functions in a base class at all, and in derived methods create a simple method and that's it! So why do we need a virtual function?

It's interesting to see an adequate and logical example, where you can see that virtual functions provide some benefit. Because what I saw was not logical, at least for me. I would like to understand it all the same.

This is the simplest sample for understanding polymorphism. To get it quickly.

There are complicated cases. You will apply it when you need it. There's no sense in bothering now. When the task is done, you'll have to think about it.

For example, I have a base class with all possible read/write interfaces. It also has private virtual methods (2 in total - read/write), which link this interface in the base class with derived classes. Actually the derived classes can be any where there is work with files (files, mapping, channels, internet). Each of the derived classes defines these virtual methods differently, but all classes have the same interface from the base class.

 
hoz:

The textbook gives this example in relation to polymorphism:

There's one thing I don't understand. If we use child function objects for calls, i.e. derived methods CCircle and CSquare, then GetArea() area can be calculated bypassing declarations in base class. I.e. do not create virtual functions in base class at all, and in derived methods create a simple method and that's it! So why do we need a virtual function?

It's interesting to see an adequate and logical example, where you can see that virtual functions provide some benefit. Because what I saw was not logical, at least for me. I want to understand it all the same.

I will try to sketch a small sample:

#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;
}

Thanks to this structure, we won't need to get into working algorithm, which can be very big and complex (everything is simplified here), we will only need to add one more descendant, m3 in enumeration and one more case in switch. That is, we have unified the input data, which will avoid editing in the main part of the program.

Of course, this will only be appropriate if the working algorithm accepts a variety of types as input. If there is only one type, all of this is useless.

 
hoz:

The textbook gives this example in relation to polymorphism:

There's one thing I don't understand. If we use child function objects for calls, i.e. derived methods CCircle and CSquare, then GetArea() area can be calculated bypassing declarations in base class. I.e. do not create virtual functions in a base class at all, and in derived methods create a simple method and that's it! So why do we need a virtual function?

It's interesting to see an adequate and logical example, where you can see that virtual functions provide some benefit. Because what I saw was not logical, at least for me. I would like to understand it all the same.

Here's a simple example:

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();
}
We use the GetArea() function without knowing which shape it is called for.
 

I have this setter in a class:

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

The compiler is generally fighting this assignment of elements to the ColorBySend array like this:

'fc_ColorSendBuy' - constant expression required        TradingFunc.mqh 91      23
'fc_ColorSendSell' - constant expression required       TradingFunc.mqh 91      40
'{' - expression expected       TradingFunc.mqh 91      22
What does this have to do with? Is it really necessary to assign values element by element? Isn't it possible to do it as a list? What is it related to? After all, that's how the assignment works even in the textbook...
 
hoz:

I have this setter in a class:

The compiler swears at this assignment of elements to the ColorBySend array in general like this:

What does this have to do with? Is it really necessary to assign values element by element? Isn't it possible to do it as a list? What does it have to do with it? After all, this is how assignment is done even in the textbook...


A construct of the {something, something else} kind can only be an array of constants. But parameters passed into the function are substituted there that are actually local variables of the function. The modifier const in this case has no meaning as it only indicates that the passed value cannot be modified. As a result
{fc_ColorSendBuy, fc_ColorSendSell}
is a variable expression which the compiler cannot understand. Alas.
 
Initialisation by list is only possible with a declaration.
Reason: