I'm assuming you are familiar with classes, member variables (instance variables) and member functions (methods).
A special member function in a class is the constructor; This function gets called automatically by the compiler when an object of that class is created. Its main purpose is to initialize the object's member variables or perform any setup required for the object to function properly.
In the Extension
class above, the constructor is:
Extension(const byte addr = 0x38) : pcf8574(addr) {}
When an object of the Extension
class is created, this constructor is called and in the given example, the Extension
class has a constructor that takes one parameter, addr
, with a default value of 0x38
. When an object of the Extension
class is created, this constructor is invoked.
if I do
Extension extender;
then extender
is the instance and the constructor got called with addr
using the default value 0x38
If I had done
Extension extender(0x40);
then extender
is the instance and the constructor got called with addr using the value 0x40
➜ the default value lets you instantiate the object without passing any parameter but you can tailor it if needed.
The constructor uses an initialization list, which is an efficient way to initialize member variables in C++.
An initialization list is written after the constructor's parameter list and is preceded by a colon, followed by a comma-separated list of member initializations. In the provided example, the initialization list
: pcf8574(addr)
initializes the member variable pcf8574
with the value of addr
.
Because pcf8574 is of type PCF8574, It specifies that the pcf8574
member should be initialized using its own constructor, with addr
as the argument. This means pcf8574
is directly constructed with the value 0x38
(or whatever value addr
has).
Using an initialization list is beneficial because it is often more efficient than assigning values to member variables inside the constructor's body. This is especially true for objects of user-defined types, such as PCF8574
in this example, where calling the constructor directly with the required parameters avoids the overhead of default construction followed by an assignment.
Note that in your case the Extension class could really be just a subclass of PCF8574 since it's a specialisation of that class. You could have written (using the same concept as initialisation list but here note the special syntax to call the parent class constructor : PCF8574(addr)
#include "PCF8574.h"
class Extension : public PCF8574 {
public:
Extension(const byte addr = 0x38) : PCF8574(addr) {}
void begin() {
pinMode(P3, OUTPUT); // LED1
pinMode(P4, OUTPUT); // LED2
pinMode(P5, OUTPUT); // LED3
pinMode(P6, OUTPUT); // LED4
pinMode(P7, OUTPUT); // LED5
}
void led1On() { digitalWrite(P3, LOW); }
void led2On() { digitalWrite(P4, LOW); }
};
// Create an instance of Extension with the default address 0x38
Extension extender;
void setup() {
extender.begin();
extender.led1On();
extender.led2On();
}
void loop() {}