Implementing print() methods within a library

Hi,

This isn’t so much a question about how to do something, it’s more a question about how to do something better.

Thanks to dc42 I’ve managed to create a library that uses LiquidCrystal.h.

To implement the print() methods in my library I’ve explicitly coded methods that directly call the LiquidCrystal object (see attached files). I’ve coded one method to print integers, and another method to print strings, these both work fine. I’ve noticed that neither the .cpp and .h files for LiquidCrystal library include any coding for print() methods, but the class definition in the .h file does include the following phrase “: public Print” after the class name. So, firstly, what does “: public Print” do? And secondly, why can’t I do something similar to implement the print methods myself in my class (I’ve tried adding “: public Print” after the class name but get an error (listed below)

LCDvario.h

#ifndef LCDvario_h                         // These lines (together with the #endif at the end of the file) prevent
#define LCDvario_h                         // any problems occuring if this library should be included twice.

extern "C" {
  #include <string.h>
}

#include <stdlib.h>                        // needed for 'free'
#include "WProgram.h"                      // needed for 'Serial'
#include <avr/pgmspace.h>                  // Needed for PROGMAN stuff
#include <ProgmemConst.h>                  // Global progmem constants
#include <Wire.h>                          // Needed for I2C comms.
#include <LiquidCrystal.h>                 // Drives the LCD screen
#include <inttypes.h>
#include "Print.h"

class LCDvario : public Print
{
  public:
    LCDvario(uint8_t rs, uint8_t enable,uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);      // Constructor
    void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);                   // initialise stuff
    //void print(int x);
    //void print(char * x);

  private:
    // Member variables

    LiquidCrystal _lcd;

};
#endif

LCDvario.cpp

extern "C" {
#include <string.h>
}
#include <stdlib.h>
//#include <cstring>                         // replacement for "extern "C" {#include <string.h>}" .... produces 'error file not found'
//#include <cstdlib>                         // replacement for #include <stdlib.h>  .... produces 'error file not found'
#include "WProgram.h"                      // needed for 'Serial'
#include <avr/pgmspace.h>                  // Needed for PROGMAN stuff
#include <ProgmemConst.h>
#include <Wire.h>
#include <math.h>                          // needed for log functions
#include "LCDvario.h"                      // Header for this library
#include <LiquidCrystal.h>                 // Drives the LCD screen
#include <inttypes.h>

LCDvario::LCDvario(uint8_t rs,uint8_t enable,uint8_t d0,uint8_t d1,uint8_t d2,uint8_t d3) : _lcd(rs,enable,d0,d1,d2,d3)
{
}

void LCDvario::begin(uint8_t cols, uint8_t rows, uint8_t charsize)
{
  _lcd.begin(cols, rows);
}

//void LCDvario::print(int x)
//{
//  _lcd.print(x);
//}
//
//void LCDvario::print(char * x)
//{
//  _lcd.print(x);
//}

The sketch…

#include <stdlib.h>                        // needed for 'free'
#include "WProgram.h"                      // needed for 'Serial'
#include <Wire.h>                          // Library to control I2C comunications
#include <avr/pgmspace.h>                  // Needed for PROGMAN stuff
#include <ProgmemConst.h>                  // Global progmem constants
#include <LiquidCrystal.h>                 // Controls access to the LCD display
#include <LCDvario.h>                      // LCD screen customised for vario use.

const int rs=8,en=9,d4=10,d5=11,d6=12,d7=13;  // Pin definitions for LCD

LCDvario lcd(rs, en, d4, d5, d6, d7);    // Display

void setup() 
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.print("Starting !");
  //lcd.print(123);

}

void loop() 
{
}

The error…

LCDvarioTest:11: error: cannot declare variable ‘lcd’ to be of abstract type ‘LCDvario’
C:\all_apps\arduino-0021\libraries\LCDvario/LCDvario.h:18: note: because the following virtual functions are pure within ‘LCDvario’:
C:\all_apps\arduino-0021\hardware\arduino\cores\arduino/Print.h:40: note: virtual void Print::write(uint8_t)

As I said, this problem isn’t a show-stopper, the two methods I’ve implemented manually work, but I’d like to know if I can do the same thing without having to code each different print method (for floats, longs, bytes etc) individually.

Thanks

So, firstly, what does “: public Print” do?

It says that the class being defined derives from another class (Print, in this case).

A derived class inherits all the properties (fields and methods) of the base class. This means that, for all intents and purposes the derived class is also the base class. Anywhere that an instance of the base class (Print) is needed, an instance of the derived class can be used.

And secondly, why can’t I do something similar to implement the print methods myself in my class

You can, if you do it right.

I’ve tried adding “: public Print” after the class name but get an error (listed below)

There are virtual classes, like Print, that declare methods (using the virtual keyword), but don't implement them. The derived class MUST provide an implementation of the virtual methods.

If you look at the Print.h file, you'll see that the write() method with one argument is declared.

If you look at the Print.cpp file, you'll see that it is called in many places, BUT, it is never implemented.

Any class that wants to derive from Print MUST implement the write() method with the signature defined in the base class.

As I said, this problem isn't a show-stopper, the two methods I've implemented manually work, but I'd like to know if I can do the same thing without having to code each different print method (for floats, longs, bytes etc) individually.

Sure. All you need to do is implement the write() method.

What you are doing by defining new methods in your class is hiding similar members defined in the base class.

Thanks PaulS,

Another top reply in lightning time! - I only wish the paid Support Services my company subscribes to were as good as this forum!

I’ve got the library working by adding this line to my header file (cut and pasted from the LiquidCrystal library)…

virtual void write(uint8_t);

And these lines to the .cpp file…

inline void LCDvario::write(uint8_t value) {
  _lcd.write(value); // invoke the write() method in the LiquidCrystal library
}

Cheers