0

Posts that I have read that are related to my question and have answered part of it:

Using 'this' keyword in constructor

Difference between using keyword new in constructor and in data portion of a class

My question:

My specific question follows on from the topic here:

Using 'this' keyword in constructor

Are the answers provided in that topic regarding ambiguity the same for C++? Does it only matter that I use this if my parameter has the same name as my field?

Here is an example with the this keyword:

    Gui::Gui()
    {
        this->organismSize = 10.0;
        this->foodSize = 5.0;
    }

Without the this keyword:

    Gui::Gui()
    {
        organismSize = 10.0;
        foodSize  5.0;
    }
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Aeryes
  • 629
  • 3
  • 10
  • 24
  • 5
    If you insist on using the same names for parameters and member variables then only the first version will work. Otherwise, it doesn't matter. – Paul Sanders May 14 '21 at 21:21
  • Now you have changed the question to make my comment invalid. I would prefer it if you didn't do that. Anyway, with your amended code, both versions have the same effect. – Paul Sanders May 14 '21 at 21:25
  • @PaulSanders The code was incorrect, if if I didnt change it then I wouldnt be asking the right question. Thanks for your answers. – Aeryes May 14 '21 at 21:29
  • The more typing your do, the higher probability of injecting defects into your code. You can avoid using `this->` syntax by choosing a naming convention that differentiates member variables from parameters, such as prepending "m_" or appending "_" to member variable names. – Thomas Matthews May 14 '21 at 21:33
  • `this` is implied when used for a member variable (because non static member variables only exist within the object created, so 'this' is always there) so the question is only depending on the scope being hidden by another variable (in your case, the parameter) – Michael Chourdakis May 14 '21 at 21:35
  • 1
    Use this keyword to resolve some ambiguity. You should first use member inizializer list : organismSize{10.0} if you do this : organismSize{ organismSize } the first is the class member and the other one is the constructor parameter. – Jimmy Loyola May 14 '21 at 21:40
  • 1
    @PaulSanders or you could initialise members in the member initialiser list, where it is unambiguous – Caleth May 14 '21 at 21:41
  • "Posts that I have read that are related to my question and have answered part of it:" The posts are **not** related to your question and **don't** answer any of your questions! The posts you linked are about C# and Java and you are asking about C++. Although somewhat related, they are different languages! Just check this topic, but for C++, e.g. https://stackoverflow.com/questions/39435693/constructor-and-this-pointer – bolov May 14 '21 at 22:02
  • @bolov They are related because they answer the issue for those languages which is why I asked if the same applies for C++ – Aeryes May 14 '21 at 22:09

2 Answers2

2

No need to use 'this' keyword in the constructor unless you have the same name for a class attribute and a parameter.

Gui::Gui(const double organismSize, const double foodSize )
{
    organismSize =organismSize; // we have an ambiguity, the compiler cannot make a difference between the parameter and the attribute
    foodSize = foodSize ;
}

Gui::Gui(const double organismSize, const double foodSize )
{
    this->organismSize =organismSize; // the compiler can make a difference between the parameter and the attribute
    //this->organismSize is the attribute while organismSize is the parameter
    this->foodSize = foodSize ;
}
2

The previous (accepted) answer is incorrect!

The main reason of using this to access the members of the class is when this class is a template, and the base class depends of the template parameter. Consider this code:

struct Base {
    Base ()
      : m_baseMember(42) {}
    int m_baseMember;
};

int m_baseMember;

struct Derived : public Base {
    Derived() {
        m_baseMember = 0;
        m_derivedMember = 0;
    }

    int m_derivedMember;
};

int main() {
    Derived d;
    cout << d.m_baseMember << ' ' << d.m_derivedMember << endl;
    return 0;
}

This code obviously outputs 0 0, as the assignment m_baseMember = 0; affects the member of the Base class.

Now a very similar code, but the base class becomes a template, and I instantiate it with int:

template<typename T>
struct Base {
    Base ()
      : m_baseMember(42) {}
    int m_baseMember;
};

int m_baseMember;

struct Derived : public Base<int> {
    Derived() {
        m_baseMember = 0;
        m_derivedMember = 0;
    }

    int m_derivedMember;
};

int main() {
    Derived d;
    cout << d.m_baseMember << ' ' << d.m_derivedMember << endl;
    return 0;
}

Again the output is 0 0. Ok, let's move on. Both Base and Derived are templates...

template<typename T>
struct Base {
    Base ()
      : m_baseMember(42) {}
    int m_baseMember;
};

int m_baseMember;

template<typename T>
struct Derived : public Base<int> {
    Derived() {
        m_baseMember = 0;
        m_derivedMember = 0;
    }

    int m_derivedMember;
};

int main() {
    Derived<int> d;
    cout << d.m_baseMember << ' ' << d.m_derivedMember << endl;
    return 0;
}

The output is 0 0 again. Nothing could go wrong with this code! One more attempt: now the Derived inherits from Base<T> (and not from Base<int>):

template<typename T>
struct Base {
    Base ()
      : m_baseMember(42) {}
    int m_baseMember;
};

int m_baseMember;

template<typename T>
struct Derived : public Base<T> {
    Derived() {
        m_baseMember = 0;
        m_derivedMember = 0;
    }

    int m_derivedMember;
};

int main() {
    Derived<int> d;
    cout << d.m_baseMember << ' ' << d.m_derivedMember << endl;
    return 0;
}

And the output is... 42 0.

That is because in this very-very-very similar code the assignment m_baseMember = 0; is being applied to the global variable. The final snippet where we explicitly use this:

template<typename T>
struct Base {
    Base ()
      : m_baseMember(42) {}
    int m_baseMember;
};

int m_baseMember;

template<typename T>
struct Derived : public Base<T> {
    Derived() {
        this->m_baseMember = 0;
        m_derivedMember = 0;
    }

    int m_derivedMember;
};

int main() {
    Derived<int> d;
    cout << d.m_baseMember << ' ' << d.m_derivedMember << endl;
    return 0;
}

The output is 0 0 again, because this->m_baseMember = 0; obviously affects the class member.

Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40
  • 1
    I'm sorry, but this looks like a very complicated way to shoot oneself in the foot. – Vincent Fourmond May 14 '21 at 22:55
  • 1
    @VincentFourmond, the way to shoot yourself in the foot is avoiding `this` whenever working with template classes. That is why MUCH safer is to access the template class members using `this`. – Dmitry Kuzminov May 14 '21 at 22:57
  • Hmmm. I get your point, but this is only going to cause troubles inside complicated hierarchies of template classes, which is probably not what the OP had in mind. – Vincent Fourmond May 14 '21 at 23:01
  • @VincentFourmond, the question was: "Is there a difference between using 'this' keyword in the constructor of a class or not using it in C++". And the MAIN reason of using `this` keyword is to access the members of template classes. That is the idiomatic way to access them, because of possible latent errors. – Dmitry Kuzminov May 14 '21 at 23:04
  • 2
    As an aside, *two-phase lookup* is the key-term. – Deduplicator May 14 '21 at 23:22