About Interfaces in Libraries

 

Just a quick question:

If I use the setup below, although not set as private, will GetSecret() be hidden from EA.mq5, since it is not defined inside Interface.mqh?

Also, will EA.mq5 ever get access to globalVar? Or can I safely declare global variables inside a library?

Thanks!

// Interface.mqh

interface IMain
{
  void Hello();
};
// Library.mq5

#property library

#include <Interface.mqh>

string globalVar = "something";

IMain *cMain() export { return (new CMain); }

class CMain : public IMain
{
public:
  void Hello() { Print("Hello!"); };
  string GetSecret()
  {
    return "secretKey";
  };
};
// EA.mq5

#include <Interface.mqh>

#import "Library.ex5"
IMain *cMain();
#import

IMain *Main;

int OnInit()
{
  Main = cMain();

  Main.Hello();

  return (INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
  delete Main;
}
 
You have the code, try it and you will get your answers.
 
Alain Verleyen #:
You have the code, try it and you will get your answers.

Well, if I call GetSecret() from  EA.mq5, it gives me a compile error.

I'm just no familiar with Interfaces and want to be SURE that there is no workaround to ever get access to GetSecret().

Can you please confirm?

 
Yannick Deubel #:

Well, if I call GetSecret() from  EA.mq5, it gives me a compile error.

I'm just no familiar with Interfaces and want to be SURE that there is no workaround to ever get access to GetSecret().

Can you please confirm?

I can't confirm that.
 
Yannick Deubel:

Just a quick question:

If I use the setup below, although not set as private, will GetSecret() be hidden from EA.mq5, since it is not defined inside Interface.mqh?

your interface by its nature is just the Abstract class with all methods being pure virtual (even if they are not defined explicitly to be such) & they should be overridden in subclasses inherited from your interface...

your string GetSecret() is not inherited from interface but is defined in subclass - it can be so. As so as you #import "Library.ex5" - this subclass CMain will be seen in your EA.mq5. And as so as GetSecret() is being situated in a public section of a class - GetSecret() will be seen in EA.mq5 ... (If you'd like to hide it - put it in a private section of the class CMain) ... 

BUT the definition should be CMain* Main; - to see it... if IMain* Main; -- will see only Hello() && perhaps typecast can help (Typecasting of Base Class Pointers to Pointers of Derivative Classes).. - but I don't like it ...

p.s. besides I'm not sure that you can import the class (or pointer to it) in mql... I know only about importing functions from the library.. & usually import from dlls...

simplified version - to input your Hierarchy to included header file

//+------------------------------------------------------------------+
//|                                                    Interface.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property strict

interface IMain
{
  void Hello();      // is pure virtual
};


string globalVar = "something";

IMain *cMain() { return (new CMain); }

class CMain : public IMain
{
public:
  void Hello() override { Print("Hello!"); };   // is overridden here
  string GetSecret()
  {
    return "I see the secretKey";
  };
};

and use of the hierarchy can be such

//+------------------------------------------------------------------+
//|                                            EA_test_interface.mq4 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include <Interface.mqh>

CMain* Main;   // <<<<<

int OnInit()
  {
//---
  Main = cMain();

  Main.Hello();
  Print(Main.GetSecret());
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
     delete Main;
  }
Typecasting - Data Types - Language Basics - MQL4 Reference
Typecasting - Data Types - Language Basics - MQL4 Reference
  • docs.mql4.com
Typecasting - Data Types - Language Basics - MQL4 Reference
 

The definition of CMain is hidden to any caller outside the library. Unless of course the caller compiles with the CMain.mqh, should any exist. 

In fact you could try an upcast on the pointer into any class of your choice that matches the object's signature. This implies private class members could not be hidden from a malicious caller if he knows about that member somehow.

 
IMain *cMain() { return (new CMain); }

anyway, I don't like this line in the header -- resembles the mixture of entities... using var of type IMain - you still (nobody knows why) return the exact CMain object...

& nobody knows why))

and besides, interface is not having the Constructor -- thus the instance of interface can not be created... but interface's goal in MQL is to define the functionality that further will be overridden in its childs...

p.s.

and typecasting concerns only class-hierarchies... not interface ... therefore my link above - just for general purposes was - not exactly your situation if you will not refactor your  interface to the class...  I see no reason to do it here, but you knows better as of the whole your project 

 

but I would likely to prefer to create a dynamic object (CERTAIN! Not Abstact type) - in OnInit & delete it in OnDeinit()

hierarchy & globals in .mqh:

//+------------------------------------------------------------------+
//|                                                    myInterface.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property strict

interface IMain
{
  void Hello();      // is pure virtual function
};


string globalVar = "something Global";


class CMain : public IMain
{
public:
   CMain() { Print("CMain created"); }
   
  void Hello() override { Print("Hello!"); };  // overriden here
  string GetSecret()
  {
    return "I see the secretKey";
  };

use in EA:

//+------------------------------------------------------------------+
//|                                            EA_test_interface.mq4 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include <test/myInterface.mqh>

CMain* objMain;   // <<<<<

int OnInit()
  {
//---
  objMain =  new CMain();
  objMain.Hello();
  Print(objMain.GetSecret());
  Print(globalVar);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   delete objMain;
  }
//+---
 
Yannick Deubel:

Also, will EA.mq5 ever get access to globalVar? Or can I safely declare global variables inside a library?

if your EA sees your library - of course it will see globalVar in it... if you want to hide globalVar from clients (e.g. EA.mq5 or others) - you should encapsulate it into the class either in private or protected section (last case will be seen only to child-classes)

 

and if you would like to have a class being used as for creation of dynamic objects (allocated On Heap) - I think it can be done something like this (with deletion of dynamic objects in destructor)

//+------------------------------------------------------------------+
//|                                                    myInterface.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property strict

interface IMain
{
  void Hello();      // is pure virtual function
};


string globalVar = "something Global from the included file";


class CMain : public IMain
{
   CMain* m_ptr;
public:
   CMain(){}
   CMain(CMain* _ptr) : m_ptr(_ptr) {             
      m_ptr=_ptr;
      
	if  (CheckPointer (_ptr) ==POINTER_DYNAMIC ) delete _ptr;
   }
   
   ~CMain() { 
   // 28 bytes of leaked memory - without this check, but with only delete m_ptr;
   if (CheckPointer(m_ptr) == POINTER_DYNAMIC)
      delete m_ptr;
   }
   
  void Hello() override { Print("Hello!"); };  // overriden here
  string GetSecret()
  {
    return "I see the secretKey";
  };
};

and used like this

//+------------------------------------------------------------------+
//|                                            EA_test_interface.mq4 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include <test/myInterface.mqh>

CMain objMain(new CMain);   // <<<<<

int OnInit()
  { 
//---
  objMain.Hello();
  Print(objMain.GetSecret());
  Print(globalVar);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   Print("still exists handler= ",GetPointer(objMain));
   // the objMain will be destroyed when EA finishes its work
  }

but anyway, global declarations & definitions are considered to be an evil - better encapsulate them & pass by-reference (in complex project) - I haven't tested yet... you can see this-  MVC design pattern

MVC design pattern and its possible application
MVC design pattern and its possible application
  • www.mql5.com
The article discusses a popular MVC pattern, as well as the possibilities, pros and cons of its usage in MQL programs. The idea is to split an existing code into three separate components: Model, View and Controller.
 

Thanks @Alain Verleyen and @JeeyCi,

But I have the scenario that the library is only available as a binary.

In my code example, the file EA.mq5 includes Interface.mqh (source code available) and the compiled version of  Library.mq5 ("Library.ex5").

With that in mind. How do I access globalVar and GetSecret() from within the EA.mq5 file?

I have tried a lot, but always failed.

I believe without the source code of Library.ex5, it is not possible to access globalVar and GetSecret().

If I'm wrong, please show me how to get access.

lippmaje #:

The definition of CMain is hidden to any caller outside the library. Unless of course the caller compiles with the CMain.mqh, should any exist. 

That's what I thought as well. (There is no CMain.mqh and Library.mq5 is not available).

lippmaje #:

In fact you could try an upcast on the pointer into any class of your choice that matches the object's signature. This implies private class members could not be hidden from a malicious caller if he knows about that member somehow.

I have tried it, but could still not access globalVar nor GetSecret().

Reason: