Help with function parameter using "&" ?

I am learning Arduino C++ and came across the following function syntax in the code snippet below;

void printInfoTo( Print & output ) // <<-- QUESTION
{
output.print( F("\nTime: ") );
if (fix.valid.time) {
if (fix.dateTime.hours < 10) output.print( '0' );
output.print(fix.dateTime.hours);
output.print( ':' );
...
}
...
}

I spent some time reading several C++ tutorials via google, but can't find
clear education as to this syntax here. It looks a lot like pass argument by
reference, and the sketch, which I post fully below (from an unrelated thread),
calls this in two different ways;

printInfoTo( Serial ); OR printInfoTo( sensorData );

So, in summary, I can clearly see that the purpose is to be able to call the
same print fuction, but have the function either end up doing;

Serial.print("my string"); // which is print to serial debug port
or else do
sensorData.print("my string"); // which is print to a file on SD card

So I figured out the result, but I can't understand the actual syntax "void printInfoTo( Print & output )".
In Googling, the function argument by reference says; void MyFunctionName( Type & Variable) { }

So is "Print" a data type in Arduino core, or is "Print" as a function argument before the "&"
simply causing a relationship to the following function body code output.print("my string");
and therefore substituting either "serial" or "sensordata" for "output" in program code?

The entire sketch that I found this in is below

#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;
unsigned int lastRTCset; // when the RTC was last set from GPS time
#undef SECONDS_PER_DAY // bad RTClib!

#include <NeoSWSerial.h>
NeoSWSerial gpsPort(3, 2);

#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix; // all the parsed pieces from GPS
unsigned int fixCount; // how many GPS updates we have received

//int TEMPERATURE_PIN = 0;   <--  I don't think the temperature device is on RX pin 0!
int TEMPERATURE_PIN = A0; // Is this what you mean?
float temp;

#include <SdFat.h>
#include <SPI.h>
const int CS_PIN = 4;
SdFat SD;
File  sensorData;

#include <Adafruit_MPL3115A2.h>
Adafruit_MPL3115A2 baro;
float baroPressure, baroAlt, baroTemp;

//-----------------------------

void setup()
{
  Serial.begin(115200);
  Serial.println( F("NeoGPS+NeoSWSerial test!") );

  baro.begin();

  pinMode( 10, OUTPUT );
  SD.begin( CS_PIN );
  sensorData = SD.open("DataFile.txt", FILE_WRITE);

  Wire.begin();

  gpsPort.begin(9600);
  gps.send_P( &gpsPort, F("PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") ); // RMC & GGA
  gps.send_P( &gpsPort, F("PMTK220,1000") ); // 1Hz

  RTC.begin();
  if (RTC.isrunning()) {
    // Set the RTC to the date & time this sketch was compiled,
    //    but *ONLY* if the build time is more recent than the RTC time.
    //    It will only set the clock forward, not back to a previous time.
    DateTime build(__DATE__, __TIME__);
    long     buildSeconds = build.secondstime();
    long     nowSeconds   = RTC.now().secondstime();
    if (buildSeconds > nowSeconds)
      RTC.adjust( build );
  } else {
    Serial.println( F("RTC is NOT running!") );
  }

} // setup

//-----------------------------

void loop() {

  //  Check for GPS characters and parse them
  if (gps.available( gpsPort )) {
  
    //  Enough characters have been received to create a new fix structure
    fix = gps.read();
    fixCount++;

    checkRTC();

    if (fixCount % 2) {
      //  Now is a good time to take some readings
      temp         = analogRead( TEMPERATURE_PIN ) * 0.48828125;
      baroPressure = baro.getPressure();
      baroAlt      = baro.getAltitude();
      baroTemp     = baro.getTemperature();

      printInfoTo( Serial );

      if (sensorData.isOpen()) {
        printInfoTo( sensorData );
        sensorData.flush(); // instead of close and re-open
      }
    }
  }
} // loop

//-----------------------------

void checkRTC()
{
  if (RTC.isrunning()) {
    //  Set the RTC from the GPS or vice versa

    if (fix.valid.time && fix.valid.date) {
    
      //  We have a valid GPS date/time, set the RTC time once per hour
      if (fixCount - lastRTCset > 60*60) {
        lastRTCset = fixCount; // wait another hour

        DateTime now( fix.dateTime.year, fix.dateTime.month, fix.dateTime.date,
                      fix.dateTime.hours, fix.dateTime.minutes, fix.dateTime.seconds );
        RTC.adjust( now );
      }

    } else {
      //  We don't have a valid GPS date/time, get it from the RTC
      DateTime now = RTC.now();

      fix.dateTime.date       = now.day();
      fix.dateTime.month      = now.month();
      fix.dateTime.year       = now.year();
      fix.dateTime.hours      = now.hour();
      fix.dateTime.minutes    = now.minute();
      fix.dateTime.seconds    = now.second();
      fix.valid.date = true;
      fix.valid.time = true;
    }
  }

} // checkRTC

//-----------------------------

void printInfoTo( Print & output )
{
  output.print( F("\nTime: ") );
  if (fix.valid.time) {
    if (fix.dateTime.hours < 10) output.print( '0' );
    output.print(fix.dateTime.hours);
    output.print( ':' );
    if (fix.dateTime.minutes < 10) output.print( '0' );
    output.print(fix.dateTime.minutes);
    output.print( ':' );
    if (fix.dateTime.seconds < 10) output.print( '0' );
    output.print(fix.dateTime.seconds);
    output.print( '.' );
    if (fix.dateTime_cs < 10) output.print( '0' );
    output.print(fix.dateTime_cs);
  }

  output.print( F("\nDate: ") );
  if (fix.valid.date) {
    output.print(fix.dateTime.month);
    output.print( '/' );
    output.print(fix.dateTime.date);
    output.print( '/' );
    output.print(fix.dateTime.full_year());
  }

  output.print( F("\nFix: ") );
  if (fix.valid.status)
    output.print( fix.status );

  output.print( F("\nLocation: ") );
  if (fix.valid.location) {
    output.print( fix.latitude(), 6 );
    output.print( ',' );
    output.print( fix.longitude(), 6 );
  }

  output.print( F("\nSpeed (knots): ") );
  if (fix.valid.speed)
    output.print( fix.speed() );

  output.print( F("\nAngle: ") );
  if (fix.valid.heading)
    output.print( fix.heading() );

  output.print( F("\nAltitude: ") );
  if (fix.valid.altitude)
    output.print( fix.altitude() );

  output.print( F("\nSatellites: ") );
  if (fix.valid.satellites)
    output.print( fix.satellites );
  output.println();

  output.print(temp);
  output.println( F("*C External") );

  output.print( baroPressure / 3377 );
  output.println( F(" Inches (Hg)") );

  output.print( baroAlt );
  output.println( F(" Meters") );

  output.print( baroTemp );
  output.println( F("*C Internal") );

} // printInfoTo

Thanks for your help.

Neal

The & operator used in method arguments is telling the compiler that it is supposed to transfer the actual variable itself instead of a copy of it, allowing the method to modify the passed variable.

void alpha(byte b)
{
  b += 10;
}

void beta(byte &b)
{
  b += 10;
}

void zeta(byte *b)
{
  *b += 10;
}

byte b = 123;

alpha(b);
Serial.println(b); //123

beta(b);
Serial.println(b); //133

zeta(&b);
Serial.println(b); //143

In the code above the method "alpha" and the reference to it will be optimized away since it does nothing. "beta" works like "zeta" but without any use of pointers.

It looks a lot like pass argument by reference

That's because it is.