gabriel garcia
gabriel garcia

Reputation: 367

How to declare and instantiate class instances as class attributes

I'm designing an Arduino project that makes use of multiple sensors so I need to create classes to abstract each sensor functionality in order to make it scalable and easy to maintain.

I should say that I'm not very experienced in C++ but I'm kind of fluent in Java and some patterns and techniques that can be applied to a wide variety of languages.

So, each sensor extends an abstract class functionality (as u'd probably guess, named Sensor) and defines how a void setup() and a T get() methods should work for each implementation.

As a result each implementation would hold an instance to the basic class of its sensor library in order to make readings whenever the T get() method is called but I can't seem to find a feasible solution for this idea since it seems I can't understand C++ constructors (even after a good amount of time invested in researching across Google and other StackOverflow questions) because I can't do:

#include <HX711_ADC.h>
HX711_ADC loadCell;
uint8_t dout = 4;
uint8_t sck = 5;

void setup() {
     loadCell = HX711_ADC( dout, sck ); // Exception
     loadCell( dout, sck ); // Exception
}

dout and sck are declared uint8_t as declared types for it's constructor as seen in HX711_ADC.h

Any idea would be greatly appreciated.

Upvotes: 0

Views: 514

Answers (3)

gabriel garcia
gabriel garcia

Reputation: 367

As posted in this question's answers, in C++ it'ss not possible to declare a variable without instantiating it so I've tried creating a pointer to an HX711_ADC variable and assigning the instance later in the void setup() method. So, a solution to my own issue would be:

#include <HX711_ADC.h>
HX711_ADC* loadCell;
uint8_t dout = 4;
uint8_t sck = 5;

void setup() {
     loadCell = new HX711_ADC( dout, sck );
}

It does compile without raising exceptions but I'm not sure if it is the best solution... anyways, I'm leaving it here instead of deleting it in case anyone finds it helpful.

[EDIT] Based on Reinstate Monica's answer I've managed to create an scalable system resulting in the following classes as an example:

#include <HX711_ADC.h>

template<typename T>
class Sensor
{
public:
    Sensor(int _id) : id(_id) {};
    virtual void setup() = 0;
    virtual T get() = 0;
protected:  
    int id;
};

class WeightSensor: public Sensor<float>
{
public:
    WeightSensor(int id, uint8_t dout, uint8_t sck) : Sensor<float>(id), sensor(dout, sck) {  }
    void setup();
    float get();
private:
    HX711_ADC sensor;
};

inline void WeightSensor::setup()
{
    sensor.start(2000);
    sensor.setCalFactor(-41.95);
    sensor.begin();
}

inline float WeightSensor::get() {
    return sensor.getData();
}

Upvotes: 0

Global variables are vile. Keep them to a minimum.

I find it cleanest to keep the entire system in a class, so:

C++11

class MySystem {
  constexpr uint8_t lc_dout = 4;
  constexpr uint8_t lc_sck = 5;
  HX711_ADC loadCell{lc_dout, lc_sck};
  //...
public:
  MySystem() { /* initialization - additional */ }
  void loop() { /* the main loop */ }
};

C++98

This is just for reference. Arduino supports modern C++ language (not the standard library for the most part, though).

class MySystem {
  enum { lc_dout = 4, lc_sck = 5 };
  HX711_ADC loadCell;
  //...
public:
  MySystem() : loadCell(lc_dout, lc_sck)
  {  /* initialization - additional */ }
  void loop() { /* the main loop */ }
};

Use

Then, you'll need a way to have a variable where you can instantiate the system at the time of your choosing - thus you need a union:

union System {
  bool dummy;
  MySystem tem;
};

System sys; // the only global variable

This is then constructed in setup(), and executed in loop():

void setup() {
  new (&sys.tem) MySystem(); // constructs the instance
}

void loop() {
  sys.tem.loop();
}

Upvotes: 0

gre_gor
gre_gor

Reputation: 6766

HX711_ADC loadCell; is constructing the object with the default constructor i.e. with no arguments.

You can pass arguments like this:

#include <HX711_ADC.h>
const uint8_t dout = 4;
const uint8_t sck = 5;
HX711_ADC loadCell( dout, sck );

void setup() {
    loadCell.begin();
}

Upvotes: 0

Related Questions