Bueno, pues eso es lo que finalmente he hecho, en lugar de un puntero lo que he creado ha sido una referencia a un objeto tipo LiquidCrystal en la clase AnimationText. Sí, ya sé que originalmente me despisté y mi gozo en un pozo ya que se me olvidó el & en la declaración y en lugar de tener una referencia lo que tenía era una copia. Por eso cuando se llamaba a lcd.setCursor() fallaba. Ya que se le decía a uno de los objetos que posicionara el cursor en un lugar y se le pedía al otro que escribiese, y este otro no se había dado por enterado del cambio de posición del cursor. Ese fallo fue el que me dio a la pista de que se me había olvidado el &. Con la corrección ambos objetos son el mismo, y lo que se le dice a uno se le dice al otro.
¿Recuerdan que he dicho una y otra vez que una referencia, una vez creada no se puede cambiar? Pues ese es un pequeño gran detalle. Porque si habiendo declarado como referencia la variable lcd definimos el constructor así:
AnimationText::AnimationText (LiquidCrystal& _lcd, int Speed) {
lcd = _lcd;
}
De nada habría servido definirla como referencia. Nos daría el mismo problema que antes con el lcd.setCursor(). (He llamado al parámetro _lcd para que se vea cual es el parámetro y cual es la variable de la clase, lcd. Y porque, si no, no estaría haciendo lo que se quiere que haga). Si bien _lcd sí es una referencia al lcd “original” con el que se invoca al constructor, lcd es una referencia que se habría creado sin hacer referencia a nadie (lo más probable es que el compilador nos de un aviso o fallo). Una vez creada se le asigna por copia el valor de _lcd. Así que volvemos a tener una copia. Ya sé que es un poco galimatías, pero lo que han de tener claro es que la variable lcd de la clase AnimationText “se crea” antes de que se ejecute el código que está definido entre las { } del constructor. Y una vez creada una referencia, esta se comporta como “la variable original”. Lo que pasa aquí es que no se le ha indicado en ningún momento cual es “la variable original”. Lo que se haga dentro de las { } ya “es demasiado tarde” para poder indicar a quién ha de hacer referencia. (Y lo más probable es que el compilador se nos queje diciendo que esa referencia no ha sido inicializada adecuadamente). Es por eso que se usa la sintaxis siguiente:
AnimationText::AnimationText (LiquidCrystal& _lcd, int Speed) : lcd(_lcd) {
}
Esto le indica al compilador que queremos que construya lcd con _lcd antes de que se ejecute el código del constructor (lo que está entre las { }). Esa forma de inicializar variables y objetos se puede usar para inicializar cualquier variable u objeto de la clase. Dependiendo de cómo esté configurado el compilador, algunos se quejan si no se ponen en el mismo orden en que se declaró en la clase. Por ejemplo, en lugar de poner:
ClaseA::ClaseA(int x, int y, String z) {
a = x;
b = y;
c = z;
}
Podríamos poner:
ClaseA::ClaseA(int x, int y, String z) : a(x), b(y), c(z) {
}
Lo que sí que no es opcional es cuando, como en nuestro caso, necesitamos inicializar una referencia. Para ello sólo lo podemos hacer como en la segunda opción.
También es necesario cuando en nuestra clase definimos un objeto que no tiene constructor por defecto o queremos construirlo con un constructor con parámetros. Por ejemplo, si en lugar de querer trabajar con una referencia al lcd lo que queremos es trabajar con un objeto lcd propio de la clase y queremos que se construya llamando al constructor con parámetros.
Entonces al declarar la variable lcd en la clase lo haremos como lo hice al inicialmente, por error, sin el &. Y en constructor sería algo tal que así (he omitido la variable Speed porque no se usaba y por claridad):
AnimationText::AnimationText (int rs, int e, int d4, int d5, int d6, int d7) : lcd(rs, e, d4, d5, d6, d7) {
}
Y en lugar de tener esto:
#include <AnimationText.h>
LiquidCrystal lcd(6, 7, 8, 9, 10, 11); // RS, E, D4, D5, D6, D7
AnimationText animationText(lcd);
Tendríamos esto:
#include <AnimationText.h>
AnimationText animationText(6, 7, 8, 9, 10, 11);
Pero ahora ya no disponemos del objeto lcd en el loop() ya que lcd sólo existe dentro del objeto animationText.
Bueno, hasta aquí la “breve” explicación.