0

I have class called HighWaterDetector:

class HighWaterDetector {
public:
    HighWaterDetector(Device* device);
    NCD2Relay ncd2Relay;
    // Output output1;
    Output outputs[2];
    CloudMsgParser cloudMsgParser;
    Device * devicePtr;
};

How do I initialize the array of "Output" objects in the constructor of HighWaterDetector?

Output class:

 class Output
{
public:
    Output(ushort relayNum, NCD2Relay* ncd2RelayPtr);
    ushort relayNum;
    OutputStatus outputStatus;
    int setOutputOn(void);
    int setOutputOff(void);
    void process(void);
    NCD2Relay* ncd2RelayPtr;
};

with output constructor looking like:

Output::Output(ushort relayNum, NCD2Relay* ncd2RelayPtr2) {
    this->relayNum = relayNum;
    this->ncd2RelayPtr = ncd2RelayPtr2;
}

I am new to C++ and not sure if I can make the HighWaterDetector Constructor look like:

HighWaterDetector::HighWaterDetector(Device* device){
    ncd2Relay = NCD2Relay();
    outputs[0] = Output(1, &ncd2Relay);
    outputs[1] = Output(2, &ncd2Relay);
    cloudMsgParser = CloudMsgParser();

}

Getting compile errors:

highWaterDetector.cpp: In constructor 'HighWaterDetector::HighWaterDetector(Device*)':
highWaterDetector.cpp:8:52: error: no matching function for call to 'Output::Output()'
 HighWaterDetector::HighWaterDetector(Device* device){
                                                    ^
highWaterDetector.cpp:8:52: note: candidates are:
In file included from highWaterDetector.h:10:0,
                 from highWaterDetector.cpp:1:
output.h:20:2: note: Output::Output(ushort, NCD2Relay*)
  Output(ushort relayNum, NCD2Relay* ncd2RelayPtr);
  ^
output.h:20:2: note:   candidate expects 2 arguments, 0 provided
output.h:17:7: note: constexpr Output::Output(const Output&)
 class Output
       ^
output.h:17:7: note:   candidate expects 1 argument, 0 provided
output.h:17:7: note: constexpr Output::Output(Output&&)
output.h:17:7: note:   candidate expects 1 argument, 0 provided
highWaterDetector.cpp: In constructor 'HighWaterDetector::HighWaterDetector(Device*)':
highWaterDetector.cpp:8:52: error: no matching function for call to 'Output::Output()'
 HighWaterDetector::HighWaterDetector(Device* device){

3 Answers 3

1

If you are using C++11 or above, You should write your code like this:

class Output
{
public:
    Output(ushort relayNum, NCD2Relay* ncd2RelayPtr);
    ushort relayNum;
    OutputStatus outputStatus;
    int setOutputOn(void);
    int setOutputOff(void);
    void process(void);
    NCD2Relay* ncd2RelayPtr;
};
class HighWaterDetector {
public:
    HighWaterDetector(Device* device);
    NCD2Relay ncd2Relay;
    // Output output1;
    Output outputs[2];
    CloudMsgParser cloudMsgParser;
    Device * devicePtr;
};

Output::Output(ushort relayNum, NCD2Relay* ncd2RelayPtr2)
    : relayNum(relayNum), ncd2RelayPtr(ncd2RelayPtr2)
{
}
HighWaterDetector::HighWaterDetector(Device* device)
    : ncd2Relay(),
      outputs{Output(1, &ncd2Relay), Output(2, &ncd2Relay)},
      cloudMsgParser(),
      devicePtr(device)
{
}

Live Demo:

Without C++11, you need to create a default constructor

Sign up to request clarification or add additional context in comments.

3 Comments

I thought about that, but wasn't sure if the outputs{Output(...), Output(...)} syntax was valid prior to C++11 or not.
See en.cppreference.com/w/cpp/language/aggregate_initialization array type isn't marked since C++11, it should be fine with C++03, in my demo, I checked it with both C++03 and C++11 mode (with flag -std)
That page says: "Until C++11, aggregate initialization could not be used in a constructor initializer list due to syntax restrictions." I have a pre-C++11 compiler where this type of array initialization DOES NOT compile. Maybe it is a gcc extension prior to C++11?
0

Firstly, I think you need to have a default constructor for Output.

The default constructor is a constructor that takes no arguments. This is what will get called for each item in the array.

Secondly, please post your constructor for HighWaterDecorator. I suspect you could initialize ncdRelay in the constructor, and pass it to construct the two Output objects in the array.

3 Comments

The HighWaterDetector constructor was posted in my question. Thanks for your help.
Ah! I didn't see that. Adding a default constructor for Output should be good enough.
How would I initialize Output with default constructor though? Output requires relayNum and ncd2RelayPtr to be passed to its constructor. Any ideas?
0

Your Output class does not have a default (no input) constructor, only a non-trivial constructor that requires input values, so you cannot declare a fixed array of Output elements.

Give Output a default constructor:

class Output
{
public:
    Output(); // <-- here
    Output(ushort relayNum, NCD2Relay* ncd2RelayPtr);
    ...
};

Output::Output() {
    this->relayNum = 0;
    this->ncd2RelayPtr = 0;
}

Alternatively, you can give your existing constructor default parameter values so it can also act as a default constructor:

class Output
{
public:
    Output(ushort relayNum = 0, NCD2Relay* ncd2RelayPtr = 0);
    ...
};

Either way, you can then do this in the HighWaterDetector constructor:

HighWaterDetector::HighWaterDetector(Device* device)
    : devicePtr(device)
{
    outputs[0] = Output(1, &ncd2Relay);
    outputs[1] = Output(2, &ncd2Relay);
}

If you don't like that, then change your outputs[] array into a std::vector instead:

#include <vector>

class HighWaterDetector {
public:
    ...
    std::vector<Output> outputs;
    ...
};

HighWaterDetector::HighWaterDetector(Device* device)
{
    ...
    outputs.reserve(2);
    outputs.push_back(Output(1, &ncd2Relay));
    outputs.push_back(Output(2, &ncd2Relay));
    ...
}

5 Comments

I'm a little confused. If output has a default constructor, how is it possible you can do "outputs[0] = Output(1, &ncd2Relay);" in your first solution?
The outputs[] array elements first get default constructed before the HighWaterDetector constructor is entered. That is what the compiler error is complaining about - a missing Output default constructor. So add one. Then, once the constructor is entered, new Output objects are constructed using your 2-input constructor, and then are copy-assigned into the array. The compiler will have generated a default copy constructor and copy assignment operator for you. Or you can define your own if needed (see Rule of Three).
Interesting... so Output can have two constructors, a default and another? How does it know to use the default first?
@Felix: a class can have as many constructors as you want, as long as they take different inputs. A default constructor has special meaning, as it is called automatically when an instance of the class is created without any input values. When you declare an array like Output output[2];, its elements still have to be constructed like any other variable. Since the array is a member of HighWaterDetector, you have to provide the array element constructor inputs in the HighWaterDetector constructor's initialization list, otherwise they get default constructed instead.
@Felix: the compiler automatically generates a default constructor for you - unless - you define a custom constructor instead, which you did.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.