To close the loop on this discussion, I have changed the implementation of Morse.h and Morse.cpp as shown below.
I do wish to associate myself with PeterH's comments. I agree with PeterH.
One issue that has not be raised in this discussion is thread safety. True, on an Arduino, we do not face the same kinds of threading and synchronization issues as we do on modern mult-core processors. Still, it's worthwhile to design classes that are thread safe. The Morse class can only be thread safe if _pin is made const and there is nothing in the class's interface to permit changes. The class is more reliable in a multi-threading context if the object is immutable. Immutable objects are quite common in C++.
It is part of the contract of the dot() and dash() functions that _pin's value will not change while the functions block on delay(). If there were a way to permit _pin's value to be changed by another thread while the thread which called dot() or dash() is blocked, the old pin would become orphaned and left in a HIGH state likely causing an error in the hardware. Synchronization issues are typically very hard-to-find, and the class's designer has an obligation to prevent such errors from happening.
Furthermore, there is no legitimate reason to have more than one Morse object associated with any pin. So, I have intentionally made its copy constructor and operator= private. The class is non-copyable. Non-copyable classes are quite legitimate in C++. So, this kind of statement is prohibited
Morse mAlias = m13;
where m13 is an existing Morse object. Having mAlias serves no purpose, and it is a potential source for bugs.
I have left the explicit on the Morse constructor, because there is no legitimate reason to permit the compiler to cast ints into Morse objects. I believe that if a client can call a constructor with a single parameter and there is no reason for the compiler to be allowed to make a cast, then the cast should be prohibited through the use of explicit.
I also made a fix to the constructor in Morse.cpp such that _pin is set in an initialization list -- not in the body of the constructor which is not best practice.
#ifndef Morse_h
#define Morse_h
#include "Arduino.h"
class Morse
{
public:
explicit Morse(int pin);
void dot();
void dash();
private:
Morse(const Morse&);
Morse& operator=(const Morse&);
const int _pin;
};
#endif
#include "Arduino.h"
#include "Morse.h"
Morse::Morse(int pin) : _pin(pin)
{
pinMode(_pin, OUTPUT);
}
void Morse::dot()
{
digitalWrite(_pin, HIGH);
delay(250);
digitalWrite(_pin, LOW);
delay(250);
}
void Morse::dash()
{
digitalWrite(_pin, HIGH);
delay(1000);
digitalWrite(_pin, LOW);
delay(250);
}