构造函数是一种特殊函数,当创建结构或类的对象时自动调用并且通常用来初始化类成员。 从更长远来看我们将只看重类,并且同样应用于架构中,除非是另行定义。构造函数的名称要与类函数的名称匹配。构造函数不需要返回类型(您可以指定空型 )。
定义类成员 – 字符串 动态数组和需要初始化的对象 – 无论如何都需要初始化,不管构造函数是否存在。
每个类可以有多个构造函数,根据参数数量和初始化列表而有所不同。需要指定参数的构造函数称为参数构造函数。
无参数构造函数被称为缺省构造函数。如果一个类中没有声明构造函数,编译器会在编译过 程中创建一个缺省构造函数。
//+------------------------------------------------------------------+ //| 处理日期的类 | //+------------------------------------------------------------------+ class MyDateClass { private: int m_year; // 年 int m_month; // 月 int m_day; // 几月几日 int m_hour; // 某天几时 int m_minute; // 分钟 int m_second; // 秒 public: //--- 缺省构造函数 MyDateClass(void); //--- 参数构造函数 MyDateClass(int h,int m,int s); };
构造函数可以在类描述中声明,然后定义主体。例如,MyDateClass的两个构造函数可以定义如下:
//+------------------------------------------------------------------+ //| 默认构造函数 | //+------------------------------------------------------------------+ MyDateClass::MyDateClass(void) { //-- MqlDateTime mdt; datetime t=TimeCurrent(mdt); m_year=mdt.year; m_month=mdt.mon; m_day=mdt.day; m_hour=mdt.hour; m_minute=mdt.min; m_second=mdt.sec; Print(__FUNCTION__); } //+------------------------------------------------------------------+ //| 参数构造函数 | //+------------------------------------------------------------------+ MyDateClass::MyDateClass(int h,int m,int s) { MqlDateTime mdt; datetime t=TimeCurrent(mdt); m_year=mdt.year; m_month=mdt.mon; m_day=mdt.day; m_hour=h; m_minute=m; m_second=s; Print(__FUNCTION__); }
在 默认构造函数,类的所有成员都使用TimeCurrent() 函数,在参数构造函数,只有小时值在使用。其他的类成员 (m_year, m_month 和 m_day) 将自动初始化当前日期。
当初始化类的对象数组时,默认构造函数有一个特殊用途。所有参数都有默认值的构造函数, 并不是默认构造函数。示例如下:
//+------------------------------------------------------------------+ //| 默认构造函数的类 | //+------------------------------------------------------------------+ class CFoo { datetime m_call_time; // 最近一次对象调用时间 public: //--- 带有默认值参数的构造函数不是默认构造函数 CFoo(const datetime t=0){m_call_time=t;}; //--- 复制构造函数 CFoo(const CFoo &foo){m_call_time=foo.m_call_time;}; string ToString(){return(TimeToString(m_call_time,TIME_DATE|TIME_SECONDS));}; }; //+------------------------------------------------------------------+ //| 脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { // CFoo foo; // 该变量不能使用 - 没有设置默认构造函数 //--- 创建 CFoo 对象的可能选项 CFoo foo1(TimeCurrent()); // 参数构造函数的显式调用 CFoo foo2(); // 带有默认参数的参数构造函数的显式调用 CFoo foo3=D'2009.09.09'; // 参数构造函数的隐式调用 CFoo foo40(foo1); // 复制构造函数的显式调用 CFoo foo41=foo1; // 复制构造函数的隐式调用 CFoo foo5; // 默认构造函数的显式调用(如果没有默认构造函数,那么带有默认值的参数构造函数被调用) //--- 接收 CFoo 指针的可能选项 CFoo *pfoo6=new CFoo(); // 动态创建对象和接收其指针 CFoo *pfoo7=new CFoo(TimeCurrent());// 另一个动态对象创建的选项 CFoo *pfoo8=GetPointer(foo1); // 现在 pfoo8 指向对象 foo1 CFoo *pfoo9=pfoo7; // pfoo9 和 pfoo7 指向一个和相同的对象 // CFoo foo_array[3]; // 该选项不能使用 - 没有指定默认构造函数 //--- 显示m_call_time值 Print('foo1.m_call_time=',foo1.ToString()); Print('foo2.m_call_time=',foo2.ToString()); Print('foo3.m_call_time=',foo3.ToString()); Print('foo4.m_call_time=',foo4.ToString()); Print('foo5.m_call_time=',foo5.ToString()); Print('pfoo6.m_call_time=',pfoo6.ToString()); Print('pfoo7.m_call_time=',pfoo7.ToString()); Print('pfoo8.m_call_time=',pfoo8.ToString()); Print('pfoo9.m_call_time=',pfoo9.ToString()); //--- 删除动态创建数组 delete pfoo6; delete pfoo7; //删除 pfoo8; // 您不需要一定删除pfoo8,因为它指向自动创建的对象foo1 //删除 pfoo9; // 您不需要一定删除pfoo9,因为它指向pfoo7相同的对象 }
如果您取消这些字符串
//CFoo foo_array[3]; // 该变量不能使用 - 没有设置默认构造函数
或
//CFoo foo_dyn_array[]; // 该变量不能使用 - 没有设置默认构造函数
然后编译器将会返回一个错误“ 默认构造函数未定义” 。
如果类有用户定义构造函数,编译器就不会生成默认构造函数。这意味着如果一个类中声明参数构造函数,但未声明默认构造函数,则您不能声明类对象的数组。编译器将返回这个脚本错误:
//+------------------------------------------------------------------+ //| 无默认构造函数的类 | //+------------------------------------------------------------------+ class CFoo { string m_name; public: CFoo(string name) { m_name=name;} }; //+------------------------------------------------------------------+ //| 脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { //--- 编译过程中收到“默认构造函数未定义”的错误 CFoo badFoo[5]; }
在该示例中,CFoo 类拥有声明的参数构造函数在这种情况下,编译器在编译过程中不能自动创建默认构造函数。同时当您声明对象数组时,假设所有对象应该自动创建和初始化。 对象自动初始化过程中,需要调用默认构造函数,但由于默认构造函数不是显式声明并且不会通过 编译器自动生成,所以不可能创建这种对象。因此,编译器在编译阶段会生成一个错误。
有一个使用构造函数初始化对象的特殊语法。结构和类成员的构造函数初始化软件(特殊结构初始化)可以在初始化列表中指定。
初始化列表就是通过逗号隔开的初始化软件列表,它在构造函数参数列表后主体前(左大括号前)的冒号后面。它有以下几点要求:
//+------------------------------------------------------------------+ //| 存储字符名称的类 | //+------------------------------------------------------------------+ class CPerson { string m_first_name; // 第一名称 string m_second_name; // 第二名称 public: //--- 空默认构造函数 CPerson() {Print(__FUNCTION__);}; //--- 参数构造函数 CPerson(string full_name); //--- 初始化列表的构造函数 CPerson(string surname,string name): m_second_name(surname), m_first_name(name) {}; void PrintName(){PrintFormat('Name=%s Surname=%s',m_first_name,m_second_name);}; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CPerson::CPerson(string full_name) { int pos=StringFind(full_name,' '); if(pos>=0) { m_first_name=StringSubstr(full_name,0,pos); m_second_name=StringSubstr(full_name,pos+1); } } //+------------------------------------------------------------------+ //|脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { //--- 收到“默认构造函数未定义”的错误 CPerson people[5]; CPerson Tom='Tom Sawyer'; // 汤姆 索亚 CPerson Huck('Huckleberry','Finn'); // 哈克贝利 费恩 CPerson *Pooh = new CPerson('Winnie','Pooh'); // 维尼熊 //--- 输出值 Tom.PrintName(); Huck.PrintName(); Pooh.PrintName(); //--- 删除一个动态创建的对象 delete Pooh; }
在这种情况下,CPerson 类有三种构造函数:
class_member (表达式列表)
在初始化列表,成员可按任意顺序排列,但所有的类成员将会根据它们公告的顺序初始化。这意味着在第三构造函数,第一个m_first_name成员将会初始化,因为它是最先公告的,并且仅在 m_second_name初始化之后。如果一些类成员的初始化取决于其他类成员的值,则应该将此考虑其中。
如果默认构造函数没有在基本类声明,而同时声明一个或多个参数函数,您应该保持调用初始化列表中的一个基本类的构造函数。它作为列表普通成员用逗号分隔并且无论初始化列表位于哪里,都在对象初始化时被最先调用。
//+------------------------------------------------------------------+ //| 基本类 | //+------------------------------------------------------------------+ class CFoo { string m_name; public: //--- 初始化列表的构造函数 CFoo(string name) : m_name(name) { Print(m_name);} }; //+------------------------------------------------------------------+ //| 派生自CFoo 的类 | //+------------------------------------------------------------------+ class CBar : CFoo { CFoo m_member; // 类成员是父对象 public: //--- 初始化列表中的默认构造函数调用父构造函数 CBar(): m_member(_Symbol), CFoo('CBAR') {Print(__FUNCTION__);} }; //+------------------------------------------------------------------+ //| 脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { CBar bar; }
例如,创建柱对象时,将会调用默认构造函数CBar(),这里首先调用父CFoo构造函数,然后是 m_member类成员的构造函数。
析构函数是一种特殊功能,当类目标被破坏时自动调用,析构函数的名称用波浪字符(~)以分类 名输入。串型数据、动态数组和目标函数,不管破坏函数是否出现,无论如何都不会初始化。如 果存在破坏函数,该行为在召回破坏者后会执行。
破坏函数总是虚拟的 ,无论虚拟值存在与否。
联系客服