Abstract class

 

Столкнулся с необходимостью в абстрактном классе:

/*abstract*/ class CAbstactMy
{
public:
   static int ID;
};

class COne : public CAbstactMy
{
public:
   static int ID;
};

class CTwo : public CAbstactMy
{
public:
   //static int ID;
};
void OnStart()
{
   COne::ID = 1;
   CTwo::ID = 2;
   CAbstactMy::ID = 9999;
   Print("COne::ID = ",COne::ID);
   Print("CTwo::ID = ",CTwo::ID);
   Print("CAbstactMy::ID = ",CAbstactMy::ID);
   Print("==========================");
}
==========================
CAbstactMy::ID = 9999
CTwo::ID = 9999
COne::ID = 1

Что статистически переменные "виртуальные" - это круто.

Но мне потребовался абстрактный класс, все внутренности которого должны обязательно быть переопределены в наследнике. При компиляции класса CTwo должна появится ошибка, что я забыл переопределить переменную ID.

 

Я долго долбился с этим с год назад. Мне жутко нравятся классы интерфейсы, типа:

class CMyClassI

{

public:

 CMyClassI() {};

~CMyClassI() {};

 

virtual int Func1() = 0;

virtual int Func2() = 0;

virtual int Func3() = 0;

 } ;

 

Увы,  MQL5 такого не допускает. Поэтому я нашел выход в конструкциях типа:

 

class CMyClassI

{

public:

 CMyClassI() {};

~CMyClassI() {};

 

virtual int Func1() { ASSERT(false); return(0) }; // Must be overriden !!!

virtual int Func2() { ASSERT(false); return(0) }; // Must be overriden !!!

virtual int Func3() { ASSERT(false); return(0) }; // Must be overriden !!!

 } ;

 

Если я забываю переопределить функцию - срабатывает ASSERT

 
Roffild:

Столкнулся с необходимостью в абстрактном классе:

==========================
CAbstactMy::ID = 9999
CTwo::ID = 9999
COne::ID = 1

Что статистически переменные "виртуальные" - это круто.

Но мне потребовался абстрактный класс, все внутренности которого должны обязательно быть переопределены в наследнике. При компиляции класса CTwo должна появится ошибка, что я забыл переопределить переменную ID.

Ну во-первых, виртуальными могут быть только методы, но не переменные, поэтому ID надо сделать приватной переменной, так что бы даже потомок не смог к ней обратиться, а вместо нее назначить виртуальный метод ID(), который уже можно было бы переопределить в потомке.

2. В MQL5 виртуальный метод обязан иметь реализацию по умолчанию, поэтому добиться ошибки от компилятора не удастся.

3. Абстрактных классов в MQL5 нет, однако их можно реализовать с помощью специального паттерна. Для этого достаточно определить конструктор в секции protected.

class CAbstract
{
   public:
      virtual int ID(){return -1;}
   protected:
     //Все, теперь CAbstract может создать только класс-потомок. 
     CAbstract(){;}
};

class COne:CAbstract
{
    public:
       //Здесь пишем свою реализацию ID;
       virtual int ID(){return 1;}
};

void OnInit()
{
   //Нельзя, конструктор CAbstract скрыт от внешнего доступа.
   //т.е. теперь это классический абстрактный класс!
   CAbstract myAbstract;
   COne myOne;
   //Будет напечатана 1, т.к. COne имеет свою реализацию ID().
   Print(myOne.ID());
}

 
C-4:
...
//т.е. теперь это классический абстрактный класс!
...

Не совсем классический, здесь грабли

CAbstract COne::fn();
Плюсь можно создать CAbstract в методах Cone, поэтому с асертами лучше.
 
220Volt:

Не совсем классический, здесь грабли

Плюсь можно создать CAbstract в методах Cone, поэтому с асертами лучше.
просто не используйте static. Кстати в приведенном примере он реально не нужен.
 
Я пока в поиске, так что варианты интересные :)