Questions about class syntax.

First, thanks in advance for any replies. I'm not having a problem with programming (at the moment :roll_eyes:). I'm just curious and I like to learn things. So, I was going through the VoltageMeter library and noticed a couple things I hadn't seen before. I thought perhaps someone here could explain.

Here's the library (I removed the preceding comments to save space),
VoltageMeter.h

#ifndef VOLTAGE_METER_INC
#define VOLTAGE_METER_INC

#include "WProgram.h"
#include "analog_reference.h"

class VoltageMeter {
  byte _pin;
  float _vMax;
  
public:
  VoltageMeter(byte pin, float vMax)
    : _pin(pin), _vMax(vMax) 
  {}
  
  int analogReadVoltage(int nSamples = 1) const {
    byte currentReference = getAnalogReference();
    setAnalogReference(INTERNAL);
    float sum = 0;
    for (int i=0; i< nSamples; i++)
      sum += analogRead(_pin);
    setAnalogReference(currentReference);
    return (sum / nSamples);
  }
  
  float voltage(int nSamples = 1) const {
    return analogReadVoltage(nSamples) / 1023.0 * _vMax;
  }
};

#endif

My first question, is VoltageMeter(byte pin, float vMax): _pin(pin), _vMax(vMax) {} listed under public: a constructor or a method? It looks like a constructor to me because there's nothing inside the brackets {}. Next question, what does : _pin(pin), _vMax(vMax) do? I've never seen variableX(variableY) before. I don't think it's a cast like int(variable) because a: neither is a type, and b: both variables used are of the same type. Last question, what does the const just before the opening bracket of the methods do, and why is it placed before the bracket as opposed to somewhere else?

Thanks again for any replies,
DigitalJohnson

My first question, is VoltageMeter(byte pin, float vMax): _pin(pin), _vMax(vMax) {} listed under public: a constructor or a method? It looks like a constructor to me because there's nothing inside the brackets {}.

It's correct that it is a constructor but the last sentence is a wrong assumption. Every method can have empty brackets, that just means there is no code for it. There are multiple reasons to do so, inheritance is one of them.

Next question, what does : _pin(pin), _vMax(vMax) do?

Initializing object variables with constructor parameters. That's just another way to write

  VoltageMeter(byte pin, float vMax)  {
    _pin = pin;
    _vMax = vMax;
  }

Last question, what does the const just before the opening bracket of the methods do, and why is it placed before the bracket as opposed to somewhere else?

It means that this method doesn't change the object's values (variables). And the placement was just a decision of the language designers, they thought it would be a good place to easily know what it should do.

The extra code on the constructor function is called the initializer list.

As C++ guarantees that all base types and class members will be fully constructed before construction of the class itself, setting the class variables inside the constructor ( inside {} ) is actually assigning them values rather than initializing them.

@pylon, there is quite a big difference, it may produce the same result, however initialization is vastly different to assignment.

The initializer list solves this problem by giving you a place to initialize the class instance variables.

The class below provides a default initializer list and a custom constructor that can initialize the variables based on input.

struct Foo{
  
  Foo() : a( 44 ), b( 45 ) {}
  Foo( int _a, char _b ) : a( _a ), b( _b ) {}
  
  int a;
  char b;
};

Foo FooA;

Foo FooB( 22, 33 );

Foo a is default initialized and has the values:
FooA.a == 44;
FooA.b == 45;

FooB uses the custom constructor and is initialized to 22 & 33.

It's correct that it is a constructor

You can tell this because the method name is the same as the class name.

There are multiple reasons to do so, inheritance is one of them.

The fact that every class must have a constructor is another (probably more important) one. If you don't supply one, the compiler will generate one, and who knows what it will do.

@pylon,

Thanks for your reply. I didn't assume it was a constructor, it was a guess. However, I did make that guess based on the empty brackets because I couldn't think of a reason for a method/function that does nothing. Now I know that empty brackets doesn't necessarily mean it does nothing. After taking another look, would it be correct to assume that it's a constructor because it has no return type?

@pYro_65

Thanks to you too. I'm learning some very useful tips here :). I know things like this will come in handy for coding future libraries. So, if I understand correctly, x(y) is an assignment of y to x? In a constructor, a colon after the parameter list denotes an initializer list, correct? Why isn't it called an assignment list? Aren't all of the variables (in this case) initialized in the parameter list and outside the method, or is that instantiation of the variables?

After taking another look, would it be correct to assume that it's a constructor because it has no return type?

It would be correct to assume its a constructor because it has the same name as the class.

Thanks PaulS, I didn't see your first post until I was done writing my last post. Got it, constructor has same name as class. :slight_smile: Another question, just out of curiosity. Consructors have no return type (not even void), but methods/functions must, correct?

Thanks,
DJ

Consructors have no return type (not even void), but methods/functions must, correct?

Correct, unless the method is the destructor - same name as the constructor but with leading ~.

I have another question (actually two). Can initializer lists be used with methods/functions? Can the x(y) syntax of assignment be used elsewhere as well? Not that I'd want to, because obviously for others like myself, it's function seemed to be ambiguous where as with y = x it's very clear what's going on. When I first saw it I thought it was as in mathmatics. Where x(y) would mean y multiplied by x. Now that I think about it, do you have to use that syntax in initializer lists, or can you use y = x instead?

It's your personal style if you want to use initializers for all object variables or just for objects of them (those not having a basic type like int). I usually only initialize the objects in the initializer list and initialize the basic variables in the body of the constructor.

And sure, you can use y = x; instead.

Thanks for knowledge guys. As always, (I'm quoting South Park here) I think I've learned something today. :wink:

C-Ya,
DigitalJohnson