我有一个名为HighWaterDetector的类:
class HighWaterDetector
{
public:
HighWaterDetector(Device* device);
Device * devicePtr;
Output * output1Ptr;
CloudMsgParser * cloudMsgParserPtr;
Output output1;
NCD2Relay ncd2Relay;
CloudMsgParser cloudMsgParser;
};
使用构造函数:
HighWaterDetector::HighWaterDetector(Device* device): ncd2Relay(), output1(1, &ncd2Relay){
}
我正在尝试在HighWaterDetector的成员初始化列表中初始化Output的实例,但是输出需要您将指针传递给NCD2Relay的实例,NCD2Relay也是类HighWaterDetector的成员。我的程序在输出构造函数内崩溃。这是错误的做法吗?我做错了什么?
输出类:
class Output
{
public:
Output(ushort relayNum, NCD2Relay* ncd2RelayPtr);
ushort relayNum;
OutputStatus outputStatus;
int setOutputOn(void);
int setOutputOff(void);
void process(void);
NCD2Relay* ncd2RelayPtr;
};
//Output Constructor
Output::Output(ushort relayNum, NCD2Relay* ncd2RelayPtr) {
this->relayNum = relayNum;
this->ncd2RelayPtr = ncd2RelayPtr; //DOESNT CRASH IF I COMMENT THIS OUT
this->outputStatus.outFail = 0;
Serial.print("Initializing output ");
Serial.println(this->relayNum);
this->setOutputOff();
}
答案 0 :(得分:4)
您是否注意到编译器警告?或者他们是否最大化? 您的成员的声明顺序可能是原因:
class HighWaterDetector
{
public:
HighWaterDetector(Device* device);
Device * devicePtr;
Output * output1Ptr;
CloudMsgParser * cloudMsgParserPtr;
Output output1; // <- This is constructed before
NCD2Relay ncd2Relay; // <- This...
CloudMsgParser cloudMsgParser;
};
但你的构造函数如下:
HighWaterDetector::HighWaterDetector(Device* device): ncd2Relay(), output1(1, &ncd2Relay){ ... }
在上面的上下文中,在ncd2Relay
的构造函数中使用output1
的地址只是使用指向未初始化对象的指针,当您最终在构造之前取消引用它时,该指针是未定义行为。因此,您需要在类定义中强制执行排序......
引用C ++标准:(强调我的)[class.base.init/13]
在非委托构造函数中,初始化继续进行 以下顺序:
首先,仅针对派生程度最高的类([intro.object])的构造函数,按顺序初始化虚拟基类 它们出现在深度优先的从左到右的遍历中 基类的非循环图,其中“从左到右”是基数的顺序 派生类中基类的外观 基说明符列表。
然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中(无论顺序如何) MEM-初始化)。
然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样无论顺序如何 MEM-初始化)。强>
最后,执行构造函数体的复合语句。
答案 1 :(得分:3)
在C ++中,初始化列表不遵循您在初始化程序中编写项目的顺序。它遵循在您的班级中声明成员的顺序。由于您将NCD2Relay
放在班级Output
之后,NCD2Relay
将在输出后初始化,即使在初始值设定项中NCD2Relay
也是如此首先因此,只需在您的类声明中的NCD2Relay
之前移动Output
。