我有一个名为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的实例,这也是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();
}
注意编译器的警告了吗?还是说它们已经开到最大了?成员的声明顺序可能是原因:
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){ ... }
在上面的上下文中,在output1
的构造函数中使用ncd2Relay
的地址只是使用一个指向未初始化对象的指针,当你最终在构造它之前解引用它时,它是未定义的行为。因此,您需要在类定义中强制排序…
引用c++标准:(强调我的)[class.base.init/13]
在非委托构造函数中,初始化在以下订单:
首先,并且仅对于最派生类([intro.object])的构造函数,虚拟基类按顺序初始化它们出现在有向对象的深度优先的从左到右遍历中基类的无环图,其中"从左到右"的顺序是基类在派生类中的外观base-specifier-list .
然后,直接基类按照它们在基指定符列表中出现的声明顺序进行初始化(与类的顺序无关)mem-initializers)。
然后,非静态数据成员按照它们在类定义中声明的顺序初始化(同样,与类定义中的顺序无关)mem-initializers)。
最后,执行构造函数体的复合语句。
在c++中,初始化器列表并不遵循你在初始化器中写入项的顺序。它遵循在类中声明成员的顺序。由于您将NCD2Relay
放在类中的Output
之后,因此NCD2Relay
将在 Output之后初始化,即使在初始化器中您将NCD2Relay
放在第一位。因此,只需将NCD2Relay
移动到类声明中的Output
之前。
您想要获取初始化时无法控制的指针的副本。我会尝试将指针指向指针,因此即使原始指针稍后被初始化,您也可以从此时获得正确的值。