2016-08-10 2 views
1

У меня есть класс с именем 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, но выход, который требует от вас пропускать указатель на экземпляр 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

Не можете ли вы инициализировать эту переменную _in_ конструктора? – ForceBru

+0

Что случилось? Неправильный дизайн. Что вы пытаетесь архивировать с этой циклической зависимостью. Действительно ли необходимо иметь эти зависимости? – KIIV

+0

Я не думаю, что это должно быть проблемой, если только конструкторы конструктора 'Output'' ncd2RelayPtr'. – molbdnilo

ответ

3

В C++ список инициализатора не вытекает порядок, в котором вы пишете детали в инициализаторе. Это скорее следует порядку, в котором участники объявляются в вашем классе. Так как вы положили свой NCD2Relay после своего Output внутри класса, тогда NCD2Relay будет инициализирован после Вывод, хотя в инициализаторе вы сначала ставите NCD2Relay. Итак, просто переместите NCD2RelayдоOutput внутри декларации вашего класса.

+0

Ты избил меня. На самом деле это ответ. Составители сегодня бросают ошибки для этих вещей. –

+0

Я переупорядочил их сейчас. Вы знаете, почему он врезался в конструктор Output? – Felix

+0

@Felix Это сбой, потому что '& ncd2Relay' не определен до тех пор, пока не начнется создание конструктора' HighWaterDetector' (в отличие от того, что он все еще находится в списке инициализаторов для 'HighWaterDetector'), по причине, о которой говорил григор; то есть конструктор 'Output' вызывается до создания' ncd2Relay', поэтому ссылка 'ncd2Relay', вероятно, является мусором. –

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 просто используя указатель на неинициализированный объект, который является неопределенным поведением, когда вы в конечном итоге разыщите его до его построения. Следовательно, Вам нужно будет следить за соблюдением упорядоченность в определении вашего класса ...

Просто цитата из стандарта С ++: (курсив мой) [class.base.init/13]

В не делегировании конструктор, инициализация протекает в следующий порядок:

  • во-первых, и только для конструктора самого производного класса ([intro.object]), классы виртуальных базовых инициализируются в порядке они появляются на глубину первой слева направо прямой ход от направленного ациклического графа базовых классов, где «слева направо» является порядком внешний вид базовых классов в производном классе базовый список-спецификатор.

  • Затем прямые базовые классы инициализируются в порядке объявления, как они появляются в списке базового спецификатора (независимо от порядка памяти-инициализаторов ).

  • Затем нестатические элементы данных инициализируются в том порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка памяти-инициализаторов ).

  • Наконец, выполняется составная инструкция тела конструктора.

+0

Программа все еще сбой при объявлении экземпляра HighWaterDetector. – Felix

+0

@Felix, вы переопределили объявления 'output1' и' ncd2Relay' в определении вашего класса? – WhiZTiM

+0

Да, на самом деле, происходит сбой в конструкторе Output. См. Выше ... Я также разместил этот конструктор. – Felix

Смежные вопросы