如何初始化 Class-实例并打印它的 public 变量?

How to initialize a Class-instance and print it's public variable?

我有以下代码:

/*  1 */    class Market {
/*  2 */    public:
/*  3 */    
/*  4 */        double foo;
/*  5 */    
/*  6 */        /* 
/*  7 */         * Constructor:
/*  8 */         */
/*  9 */        Market() {
/* 10 */            foo = 2;
/* 11 */        }
/* 12 */    };
/* 13 */    
/* 14 */    Market market;              // GLOBALLY VISIBLE VAR
/* 15 */    
/* 16 */    void OnInit() {             // OnInit event-process
/* 17 */      market = new Market();    // <------------------- 17,10
/* 18 */      Print(market.foo);
/* 19 */    }
/* 20 */    
/* 21 */    void OtherFunc() {
/* 22 */      Print(market.foo);
/* 23 */    }

然而,当我尝试编译时,出现以下错误:

test.mq4(17,10) : error 280: '=' - object required

基本上我打算创建一个对象实例并接收指向它的指针,这样我就可以在整个代码中全局使用它。

我已经检查了 MQL4 docs page 关于 class 的内容,但它对我没有帮助。

我还尝试将 class 分配为:

Market *market = new Market();

然后我在第一行声明了这个变量:

Market market;

但是我收到了这个警告:

test.mq4(17,11) : warning 62: declaration of 'market' hides global declaration at line 14

并且文件可以编译,但我不想隐藏全局声明(因为它在其他函数中不可用),我想将一个对象实例分配到全局声明,所以我可以在整个代码中打印对象的变量。

我该怎么做?

那么,让我们开始"inventory of don't-s"进阶-MQL4

第一个建议,从不依赖网络资源,总是检查自动更新IDE-Help。即使这不包含 100% 正确的文本/代码示例,但它比过时的网络文本更接近实际的编译器语法。

下一个建议,总是记住MQL4不是C语言 - 奇怪的差异可能会杀死其他人聪明的主意。


语法优先:

Object Create Operator new

The new operator automatically creates an object of a corresponding size, calls the object constructor and returns a descriptor of created object. In case of failure, the operator returns a null descriptor that can be compared with the NULL constant.

The new operator can be applied only to class objects. It can't be applied to structures.


Object Pointers

In MQL4, there is a possibility to dynamically create objects of complex type. This is done by the new operator, which returns a descriptor of the created object. Descriptor is 8 bytes large. Syntactically, object descriptors in MQL4 are similar to pointers in C++.

Examples:

MyObject* hobject= new MyObject();

In contrast to C++, the hobject variable from example above is not a pointer to memory, but rather an object descriptor. Furthermore, in MQL5 all objects in function parameters must be passed by reference.


保留在全局范围内可见的值 NEXT:

使用上面的方法,hobject 应该在全局范围内可见,假设它的声明在适当的位置,在任何系统事件处理程序/用户之前定义的代码开始(当然,条件是在代码的任何较低级别范围内没有发生名称屏蔽)。

结语:

在接触了一些 hundreds man*yearsMQL4 实践经验之后,所有高级解决方案都开始设计为分布式框架,而不必继续成为语言不规则和语法错误的受害者。人们可能认为这是一种比在生态系统中投入大量软件工程更安全的选择,生态系统的变化速度比重复代码库重新设计的经济/性能可能设法跟上移动沙子的步伐要快。

无论如何: 欢迎来到[=的狂野世界10=]

全局变量的声明应该是这样的:

Market *market;

然后要初始化 class(例如在 OnInit() 中),您应该这样做:

market = new Market();

然后打印 class 变量(例如 market.foo)或照常调用方法(例如 market.Foo())。

让我们逐个详细说明案例:


故事中比较重要的部分:

class 语法为 O[=80 的 非常重要的概念 提供了方法=]bject-Oriented-Design 思维模式。这里的对象边界,作为一个主要的保护屏障,而不仅仅是下一个语法糖玩具(虽然一些语言确实强制执行这个主要的访问屏障保护,以绝对隔离的方式保存对象的内部世界外部尝试 "directly" 与 class 实例变量交互(例如 SmallTalk 以出色的水平做到这一点)一些其他语言,开始几十年后,他们首次访问 OOP 领域时,在思维概念上并没有表现出如此清晰,并且可能允许 "hybrid"-access(这可能并且确实混淆了很多关于冲突编程实践,这有点绕过了原始 principal OOD 架构的好处——编程/测试团队方面的所有这些都面临着全部风险。

   // DEMO                GetFoo:
      public: double DEMO_GetFoo(){ return( aClassVARIABLE_foo );
                                    }

甚至直接打印<class-method>

   // DEMO         PrintActualFooVALUE:
      public: void PrintActualFooVALUE(){ PrintFormat( "Value of foo == %23.10f",
                                                       aClassVARIABLE_foo
                                                       );
                                          }

更多的是 OOD,保护 private: double aClassVARIABLE_foo; 免受外部世界的影响,而不是普遍授予的 public 允许通过裸露(自由暴露)破坏珍贵的物体玩具 public: double foo;.

BEST PRACTICE: KEEP THE BENEFITS OF THE CORE MOTIVATION FOR OOD
If one may do so,
rather prefer to avoid such dangers and fine tune one's own OOD craftsmanship.

Why? For a sake of an academic OOD-purity?
No.

The first need to change an unimportant implementation detail inside a class will teach one, why the very due separation of the inner-world of the object and the outer-world of the extra-object reality is important.

The access via <class-methods> completely prevents and principally avoids any code-base impacts outside of the modified class right because the access <class-methods> reflect & mediate all internal changes accordingly, without the external worlds were ever in a need to know details about the real internal class-representation of (an assumed only double ) foo or whatever more complex stuff one needs to handle.

使用
通过class-方法访问,
而不是分配给裸public: <class-variable>
代码
可能看起来像这样:

//+------------------------------------------------------------------+
//|              ___Whosebug_OOP_class_public_variable_DEMO.mq4 |
//|                                       Copyright © 1987-2016 [MS] |
//|                                                       nowhere.no |
//+------------------------------------------------------------------+ >>> 
#property copyright "Copyright © 1987-2016 [MS]"
#property link      "nowhere.no"
#property version   "1.00"
#property strict

class DEMO_Class_Market {
   // public:
      private:
                  double   aClassVARIABLE_foo;
   // DEMO GetFoo:
      public:     double   DEMO_GetFoo(){       
                              return( aClassVARIABLE_foo );
                           }
   // DEMO ChgFoo:
      public:     double   DEMO_ChgFoo( double aNewVALUE_to_SET  = EMPTY_VALUE ){
                              double aTempRetVALUE = aClassVARIABLE_foo;
                                                     aClassVARIABLE_foo   = aNewVALUE_to_SET;
                              return( aTempRetVALUE );
                              }
   // DEMO_<Constructor>:
      DEMO_Class_Market(){
                           PrintFormat( "DEMO_Class_Market::<Constructor> has initially seen a variable foo == %23.10f", aClassVARIABLE_foo );
                           aClassVARIABLE_foo = 2.;
                           PrintFormat( "DEMO_Class_Market::<Constructor> has set a new value into var. foo == %23.10f", aClassVARIABLE_foo );
                           }
   // DEMO_<Destructor>:
     ~DEMO_Class_Market(){  
                           PrintFormat( "DEMO_Class_Market::<Destructor>  has seen a current value of a foo == %23.10f", aClassVARIABLE_foo );
                           }
      };

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void  OnStart(){

      DEMO_Class_Market anInstanceOfMARKET;

      double            anExternalQueryForClassVariableVALUE = EMPTY;

      int               aReturnCODE = GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, anExternalQueryForClassVariableVALUE );
      PrintFormat(      "1.st call to GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, ... ) function. The actual call returned [aReturnCODE == %d ], the anExternalQueryForClassVariableVALUE is == %23.10f", aReturnCODE, anExternalQueryForClassVariableVALUE );

                        aReturnCODE = ChgClassInstancePublicVariableVALUE( anInstanceOfMARKET, 6666.6666, anExternalQueryForClassVariableVALUE );
      PrintFormat(      "1.st call to ChgClassInstancePublicVariableVALUE( anInstanceOfMARKET, 6666.6666 ) function. The actual call returned [aReturnCODE == %d ], the returned previous value of a class-[private] variable was == %23.10f", aReturnCODE, anExternalQueryForClassVariableVALUE );

                        aReturnCODE = GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, anExternalQueryForClassVariableVALUE );
      PrintFormat(      "2.st call to GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, ... ) function. The actual call returned [aReturnCODE == %d ], the anExternalQueryForClassVariableVALUE is == %23.10f", aReturnCODE, anExternalQueryForClassVariableVALUE );
   }
//+------------------------------------------------------------------+
#define RET_OK    0
#define RET_ERROR EMPTY
#define VAL_ERROR EMPTY_VALUE
//+------------------------------------------------------------------+
int   GetClassInstancePublicVariableVALUE( DEMO_Class_Market       &aClassINSTANCE, //   |-> DEMO_Class_Market INSTANCE = <aClassINSTANCE> of a type DEMO_Class_Market
                                           double                  &aDoubleVALUE    // <=|   returns RESULT = ???.???
                                           ){
      aDoubleVALUE = aClassINSTANCE.DEMO_GetFoo();                                  // STOR <class-method> RET VALUE IN RESULT
      return( RET_OK );                                                             // FLAG RET_OK in JIT/RET
   }
//+------------------------------------------------------------------+
int   ChgClassInstancePublicVariableVALUE( DEMO_Class_Market       &aClassINSTANCE,       //   |-> DEMO_Class_Market INSTANCE = <aClassINSTANCE> of a type DEMO_Class_Market
                                           double const             aNewDoubleVALUEtoSET, //   |-> a value to SET
                                           double                  &aReplacedVALUE        // <=|   returns an OLD value
                                           ){
      aReplacedVALUE = aClassINSTANCE.DEMO_ChgFoo( aNewDoubleVALUEtoSET );                // CHNG NEW VALUE IN VARIABLE via <class-method>, RET OLD VALUE
      return( RET_OK );                                                                   // FLAG RET_OK in JIT/RET
   }
//+------------------------------------------------------------------+

[MT4 终端] 的结果按时间流重新排序

2016.11.03 14:35:37.655 Script ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: loaded successfully
2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: initialized
2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: DEMO_Class_Market::<Constructor> has initially seen a variable foo ==            0.0000000000
2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: DEMO_Class_Market::<Constructor> has set a new value into var. foo ==            2.0000000000

2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: 1.st call to GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, ... ) function. The actual call returned [aReturnCODE == 0 ], the anExternalQueryForClassVariableVALUE is ==            2.0000000000

2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: 1.st call to ChgClassInstancePublicVariableVALUE( anInstanceOfMARKET, 6666.6666 ) function. The actual call returned [aReturnCODE == 0 ], the returned previous value of a class-[private] variable was ==            2.0000000000

2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: 2.st call to GetClassInstancePublicVariableVALUE( anInstanceOfMARKET, ... ) function. The actual call returned [aReturnCODE == 0 ], the anExternalQueryForClassVariableVALUE is ==         6666.6666000000

2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: DEMO_Class_Market::<Destructor>  has seen a current value of a foo ==         6666.6666000000
2016.11.03 14:35:37.655 ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: uninit reason 0
2016.11.03 14:35:37.655 Script ___Whosebug_OOP_class_public_variable_DEMO XAUUSD,H1: removed

声明 无论是在全局/局部范围 不需要任何其他语法修改:

可以通过相互排斥(未)注释的前者和后者声明实例来测试两种声明替代方案。

.
..
...
DEMO_Class_Market anInstanceOfMARKET;  // DECLARE'd on a global scope

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void  OnStart(){

   // DEMO_Class_Market anInstanceOfMARKET;  // DECLARE'd on a local scope
...
..
.

故事中不太重要的部分:
(cit.) "practical code example how to assign/attach an object instance to the global variable."

It has been shown in the above posted MQL4 code in practice,
as was requested in the bounty reasoning paragraph,
that a class-instance can be freely attached to an MQL4 variable existing on either a global scope or a local scope.

In case, one needs some context-specific initialisations to be executed upon a code-execution visit to an OnInit() event-handler,
one may rather design an additional ( almost-pythonic :o) ) <class-method>
public: void __init__( ... ){ ... }
to receive additional levels of control
for such context-specific / MT4-state-aware <class-instance> initialisation customisations during OnInit() and request there a call to anInstanceOfMARKET.__init__( ... ); once the [ MetaTrader Terminal 4 ] graph details have become known and it's parameters and other digital content have become accessible from the live-execution of the MQL4-code ( which is not guarranteed in the moment, where a class-instantiation process happens right at the code of the declaration in the place feasible for a definition on a global scope ).