lundi 25 janvier 2016

Initialise complex object

What options are available to create an object with lots of parameters in the global namespace? I'm thinking of the tradeoff between temporary object/variable creation and readability.

This is for embedded programming on the Arduino. It probably doesn't matter too much for what I am doing, but would like to know the best practices.

Feel free to constructively criticise my code!

The two options that I can think of are:

  1. A constructor with lots of parameters.
  2. A constructor with a single struct parameter.

Option 1 looks messy and hard to follow with lots of parameters.
Option 2 requires a temporary struct variable for readability.

Example below (normally I would separate into headers etc.):

#include <Arduino.h>
class NestedClass {
public:

  // Empty constructor for creation of unitialised object. Bad practice?
  NestedClass() {
  }

  // Main constructor.
  NestedClass(float voltageReference) :
      voltageReference_(voltageReference) { // Use initialisation list.
  }

  float measureVoltage(uint_fast8_t channel) {
    // Convert ADC value to absolute voltage.
    return analogRead(channel) * (voltageReference_ / 1024);
  }

private:
  float voltageReference_;
};

class ComplexClass {
public:

  enum class Mode
    : uint_fast8_t {
      MODE1,
    MODE2,
    MODE3
  };

  struct Parameters {
    uint_fast8_t parameter1;
    uint8_t parameter2;
    float parameter3;
    float parameter4;
    Mode mode;
    float voltageReference;
  };

  // Empty constructor for creation of unitialised object. Bad practice?
  ComplexClass(void) {
  }

  // Big constructor. Messy when used.
  ComplexClass(uint_fast8_t parameter1, uint8_t parameter2, float parameter3,
      float parameter4, Mode mode, float voltageReference) {
    // Could have used initialisation list instead.
    this->parameter1_ = parameter1;
    this->parameter2_ = parameter2;
    this->parameter3_ = parameter3;
    this->parameter4_ = parameter4;
    this->mode_ = mode;
    this->nestedClass_ = NestedClass(voltageReference); // Wasted temporary object with reassignment?
  }

  // Alternative constructor. Looks neater/more legible when used.
  ComplexClass(Parameters parameters) {
    this->parameter1_ = parameters.parameter1;
    this->parameter2_ = parameters.parameter2;
    this->parameter3_ = parameters.parameter3;
    this->parameter4_ = parameters.parameter4;
    this->mode_ = parameters.mode;
    this->nestedClass_ = NestedClass(parameters.voltageReference); // Wasted temporary object with reassignment?
  }

  void megaMeasurements() {
    // Do something involving nestedClass.measureVoltage().
  }

private:
  // Maybe put all of these in another struct for neatness?
  uint_fast8_t parameter1_;
  uint8_t parameter2_;
  float parameter3_;
  float parameter4_;
  Mode mode_;

  NestedClass nestedClass_;
};

//####################
// Start main code.
//####################

// Option 1:
// Not immediately obvious which value is for which parameter.
ComplexClass complexClass(1, 2, 3.30, 2.7, ComplexClass::Mode::MODE2, 5.00);

// Option 2:
// Unitialised object (sort-of).
ComplexClass complexClass2;

// Arduino standard function. Called once from main.cpp
void setup() {
  // Option 2 continued:
  ComplexClass::Parameters parameters;
  parameters.mode = ComplexClass::Mode::MODE2;
  parameters.parameter4 = 3.30;
  parameters.parameter1 = 1;
  parameters.parameter2 = 2;
  parameters.parameter3 = 3.30;
  parameters.parameter4 = 2.7;
  parameters.voltageReference = 5.00;
  complexClass2 = ComplexClass(parameters); // Reassignment. Wasteful?
}

// Arduino standard function. Called in a continuous loop after setup().
void loop() {
  complexClass.megaMeasurements();
  complexClass2.megaMeasurements();
}

Aucun commentaire:

Enregistrer un commentaire