2

我有一个名为 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 的实例,但 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();
}
4

2 回答 2

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-initializers 的顺序如何)。

  • 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管 mem-initializers 的顺序)。

  • 最后,执行构造函数体的复合语句。

于 2016-08-10T21:11:21.020 回答
3

在 C++ 中,初始值设定项列表不遵循您在初始值设定项中写入项目的顺序。它而是遵循在您的类中声明成员的顺序。既然你把你放在你NCD2RelayOutput类里面,那么NCD2Relay将在输出之后被初始化即使在你放在NCD2Relay第一个初始化器中。所以,在你的类声明NCD2Relay 之前移动。Output

于 2016-08-10T21:10:40.457 回答