I'm learning several languages. 5 at once but I took a liking to one specific feature of java. The This keyword.

From their tutorial:

/*Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called. You can refer to any member of the current object from within an instance method or a constructor by using this.

Using this with a Field

The most common reason for using the this keyword is because a field is shadowed by a method or constructor parameter.

For example, the Point class was written like this*/

public class Point {
    public int x = 0;
    public int y = 0;

    //constructor
    public Point(int a, int b) {
        x = a;
        y = b;
    }
}

//but it could have been written like this:

public class Point {
    public int x = 0;
    public int y = 0;

    //constructor
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Why can't we do this in C++? The compiler says it's ambiguous or that the parameter x shadows a member of such and such class.
Is there any tricks to doing this?

Also another thing I'd like to know:

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(0, 0, 0, 0);
    }
    public Rectangle(int width, int height) {
        this(0, 0, width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    ...
}

In the above, they use the this keyword to call another constructor of the exact same class! I read somewhere that it's bad to do this in c++ and that it's better to make a new object and just assign it to the current one. Is this true or can I actually do this in C++?

Recommended Answers

All 6 Replies

Is this true or can I actually do this in C++?

One of the reasons why this is reasonable in Java is the lack of default arguments. In C++ you can do it all with one constructor:

Rectangle(int width = 0, int height = 0, int x = 0, int y = 0)
    : width(width), height(height), x(x), y(y)
{
    // Nothing necessary in the body
}

Note that I swapped x and y with width and height. For one thing I think it makes more sense conceptually, but also to support the second variant of Rectangle() from your Java code more easily.

Ahh but if I do that, what happens when I access the values in the body?

Rectangle(int width = 0, int height = 0, int x = 0, int y = 0) : width(width), height(height), x(x), y(y)
{
    x = 500;  //does it assign to the x within the class? Does it assign to the parameter x?
    y = 500;

    Point(x, y);  //which x/y does it use? How will the compiler know which is which? do I use this.x?
}

Ahh but if I do that, what happens when I access the values in the body?

If the parameter names are the same as the data member names, the parameters will hide the data members when unqualified. This ambiguity doesn't exist in the initializer list, and it can be corrected in the body by qualifying with this:

this->x = x;
this->y = y;
Point(this->x, this->y); // But Point(x, y) works too since the values are the same
Rectangle(int width = 0, int height = 0, int x = 0, int y = 0) : width(width), height(height), x(x), y(y)
{
x = 500; //does it assign to the x within the class? Does it assign to the parameter x?
y = 500;
Point(x, y); //which x/y does it use? How will the compiler know which is which? do I use this.x?
}

I think you're approaching this back to front. Rather than dump code onto the page then ask, "but what does it do?", first decide what it is you want to do, then learn the language features that enable you to do it. Understandably, different languages will do things in a different way.

All this is (conforming) C++:

struct A
{
    // http://www.stroustrup.com/C++11FAQ.html#default
    // http://www.stroustrup.com/C++11FAQ.html#constexpr
    constexpr A() = default ; // x == 0, y == 0

    constexpr explicit A( int x ) : x(x) {} // A::x==x A::y==0

    A( int x, int y )
    {
        A::x = x ;
        this->y = y ;
    }

    private:
        int x = 0 ; // http://www.stroustrup.com/C++11FAQ.html#member-init
        int y = 0 ;
};

struct B
{
    // http://www.stroustrup.com/C++11FAQ.html#delegating-ctor
    constexpr B() : B(0,0,0) {}

    constexpr explicit B( int x ) : B(x,0,0) {}

    constexpr B( int x, int y ) : B( x, y, 0 ) {}

    constexpr B( int x, int y, int z ) : x(x), y(y), z(z) {}

    private:
        int x ;
        int y ;
        int z ;
};

struct C : B
{
    // http://www.stroustrup.com/C++11FAQ.html#inheriting
    using B::B ; // a is initialized with 9 when we use an inherited construtor

    constexpr C( int x, int y, int z, int a ) : B(x,y,z), a(a) {}

    private: int a = 9 ;
};

Why can't we do this in C++? The compiler says it's ambiguous or that the parameter x shadows a member of such and such class.
Is there any tricks to doing this?

The this pointer exists in C++ too (Java copied this feature from C++). You can access the members as this->x or this->y. The compiler is always going to complain about the shadowing of the member by the parameter if they have the same name, just to make sure you are aware that addressing x is not going to address this->x but the parameter. The easiest way to avoid this is to just use a different name for the parameter. Personally, I often just add a "a" in front and use a CamelCase for the parameters, in this case it would be aX. There are other conventions, like putting a trailing underscore for parameters, as in x_.

In the above, they use the this keyword to call another constructor of the exact same class! I read somewhere that it's bad to do this in c++ and that it's better to make a new object and just assign it to the current one. Is this true or can I actually do this in C++?

In C++, it is true that you should never call a constructor directly, and I don't think you would be allowed too, but it is possible through the placement-new syntax. Certainly, you should not call another constructor within one constructor, using the placement-new syntax on the this pointer. Either use default parameters, or use a new feature of C++ (C++11) which is called delegating constructors which does exactly what you describe (but you'll need GCC 4.7 or more to have this feature, or CLang 3.0 or more). Or, use an init function, as in the example in the link.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.