Member functions of a class

what about it ? member initializer lists can have multiple initialisations

ClassName (int x, int y, int z) : x(x), y(y), z(z) {}

when you write x(x) the rule is that the first x is the member's variable and the second x is the parameter. (they don't need to have the same name)

guessing this is one of the many features of C++ that Stroustrup warned against (3rd ed) using just for the sake of using them.

what is the benefit of thi feature over other approaches?

is this syntax going to be easily understood by most people on this forum? How commonly used is It?

you mean what's the benefit of

ClassName (int x, int y, int z) : x(x), y(y), z(z) {}

versus

ClassName (int x, int y, int z) {
  this->x = x;
  this->y = y; 
  this->z = z; 
}

The benefit of using the first version (member initializer list) is primarily related to performance and initialization behavior. In the initializer list, member variables are initialized directly, while in the second version they are first default-constructed and then assigned values. If they were not int but complex classes where you need to pass some parameters, that could also be a challenge (complex objects or types that don't have default constructors)

it should as this is the best way to write an initializer. for example const and reference members must be initialized during construction and cannot be assigned later. The initializer list is the only way to initialize them

Also, for initializing the base class(es).

indeed

the nuances are not obvious.

guessing that there are cases where initializing some (types of?) private variables can't be done explicitly as i've suggested in a constructor?

Here's a pretty good summary: https://www.geeksforgeeks.org/when-do-we-use-initializer-list-in-c/

yes, imagine you have a constant member and you want to pass the value to the constructor or a class with a constructor that needs parameters

you're saying you can't assign a value to a constant the way i suggested, but it can be assigned a value using an initializer list

not everyone is a neophyte.

???

Yes. let's see an example

class A {
  private:
    const int constant;

  public:
    A(const int constantValue) : constant(constantValue) {}
    // A(const int constantValue) {constant = constantValue;} // error: assignment of read-only member 
    void print() {
      Serial.print("constant = ");
      Serial.println(constant);
    }
};

// various ways of writing code  to instantiate an A
A a1(42);  // Direct initialization
A a2{42};  // prevents certain implicit type conversions and helps avoid narrowing conversions
A a3 = 42; // not recommended — the process involves creating a temporary object and copying it to a3

void setup() {
  Serial.begin(115200);
  a1.print();
  a2.print();
  a3.print();
}

void loop() {}

the constructor with the initializer list works whereas you'll get an "error: assignment of read-only member" if you go for the assignment in the constructor's body.

2 Likes

an additional example to build onto the previous one.

As we have seen you can't instantiate A without a parameter

Imagine you have a class B and you want B to have an instance variable of type A.

➜ you can't write the constructor of B without an initializer list.

class A {
  private:
    const int constant;

  public:
    A(const int constantValue) : constant(constantValue) {}
    // A(const int constantValue) {constant = constantValue;} // error: assignment of read-only member
    void print() {
      Serial.print("constant = ");
      Serial.println(constant);
    }
};

class B {
  private:
    A a;
  public:
    B(const int aConstant) : a(aConstant) {}
    // B(const int aConstant) {a(aConstant);} // error: no matching function for call to 'A::A()'
    void print() {
      Serial.print("from B, ");
      a.print();
    }
};

A a(42);
B b(84);

void setup() {
  Serial.begin(115200);
  a.print();
  b.print();
}

void loop() {}

the error you'd get if you try to compile with the commented out constructor would be error: no matching function for call to 'A::A()' because the class tries to build its instance variables and so tries to first call a default constructor for a and there is none.

2 Likes

getting back to your less personal statement

i provide examples using C which i believe most people on this forum struggle with and can learn from, if not immediately can become aware of

initializer list seems to be a more advanced feature of C++, a more esoteric feature as @J-M-L has now described. While they may be using libraries based on clases, it seems that C++ is beyond what most people, the neophytes on this forum are writing code for

so i learned a bit more about C++

This discussion primarily revolves around object-oriented programming, making the mention of initializer lists quite relevant. By consistently applying best practices for constructors, newcomers can gain valuable insights, while seasoned C programmers may be inspired to explore new concepts.

Adhering strictly to C, despite the platform being compiled with a C++ compiler and the common use of class instances through various libraries (often without a full understanding, I agree) limits perspective significantly.

Challenging one's mind is always beneficial, especially as we grow older...

@UKHeliBob, bear in mind that default values can be problematic...
https://www.google.com/search?q=default+parameters+problems

So much so that the Rust folks have excluded the feature until the problems can be resolved despite the convenience.


...versus...

The question to ask when deciding what arguments should be included for constructors... Is the {whatever} a valid {whatever} without that value?

In this case, can a Train be nameless? If "no" then just the second constructor is the correct choice. Name is required so it should be impossible to create a Train without a name.

If "yes" then the first constructor is the correct choice with a setName method. You may want to also include the second constructor as a convenience. But, you may want to instead consider a TrainBuilder class for constructing Trains or you may want to support chained setters.

In other words, choose constructor parameters wisely and cautiously.

but some suggest that even using features of C (e.g. structs, enums, dare i say arrays, or pointers) is too confusing for the typical Arduino newbie.

i think, but have been chastised, that showing how some feature of the language someone appears unfamilar with can make their program simpler, is a good thiing, at the very least making them aware of it, even if not understandable at the time.

some newbie code is so convoluted that i think it makes sense to just demonstrate a different approach.

I don't see the harm, the OP is free to ignore the post. is there just one acceptable approach for responding to a post? is there just one type of newbie?

but, but, but ... haven't you said enough?

1 Like

I'd like to read more about that. Which of the hits in that search provides a concise explanation?

Fair point

Agreed also that the default parameters for constructors is not the best idea

1 Like