简体   繁体   中英

Why this doesn't work in c++ constructors

I am trying to refresh my c++ so I decided to write a class with all the constructors but then I realised that it is not possible to reuse previously defined constructors(eg :this(arg1,arg2){} like c#).

So I tried this where the first is the header file and the second is the implementation file:

Header file:

class Point
{
public:
       int get_x() const;
       void set_x(int);

       int get_y() const;
       void set_y(int);

       Point(int, int);
       Point();
       Point(const Point&);
       ~Point();
private:
        int x_coord, y_coord;

};

Implementation file:

int Point::get_x() const
{
    return this->x_coord;
}
void Point::set_x(int x)
{
     this->x_coord = x;
}

int Point::get_y() const
{
    return this->y_coord;
}
void Point::set_y(int y)
{
     this->y_coord = y;
}

Point::Point(int x, int y)
{
  this->set_x(x);
  this->set_y(y);
}

Point::Point(const Point& p)
{
  Point(p.get_x(), p.get_y());
}

// class constructor
Point::Point()
{
  Point(0, 0);
}

// class destructor
Point::~Point()
{
    // insert your code here
}

And then in the main.cpp I do this:

int main(int argc, char *argv[])
{

    Point a = Point(2, 3);
    Point b = Point(); 
    Point c = Point(a);

    system("PAUSE");
    return EXIT_SUCCESS;
}

Where only the 'a' object gets initialized correctly but the other two have these random values and don't get initialized the way I want them to be.

These two lines

Point(p.get_x(), p.get_y());

and

Point(0, 0);

do not do what you think they do: rather than invoking the corresponding constructor on the object being initialized, they create a new, unrelated temporary object, which gets discarded right away. The members of the Point being created remain uninitialized.

You could fix this by defining a private function that does initialization. If you have access to a modern C++ compiler, you could also use C++11 standard: which allows you to "chain" constructors .

In this constructor

Point::Point()
{
  Point(0, 0);
}

expression statement

  Point(0, 0);

creates a temporary object of type Point and deletes it at once. So the data members of the original object will not be initialized.

There is the same problem with the copy constructor

Point::Point(const Point& p)
{
  Point(p.get_x(), p.get_y());
}

What you want is the following

Point::Point(int x, int y) : x_coord( x ), y_coord( y )
{
}

Point::Point(const Point& p) : x_coord( p.x_coord ), y_coord( p.y_coord )
{
}

// class constructor
Point::Point() : Point( 0, 0 )
{
}

The last constructor is the same constructor as in C# that uses delegating only there is used the class name for naming the constructor instead of the keyword this.

Take into account that instead of

Point a = Point(2, 3);
Point b = Point(); 
Point c = Point(a);

it would be better and simpler to write

Point a(2, 3);
Point b; 
Point c = a;
Point::Point(const Point& p)
:  Point(p.get_x(), p.get_y())
{
}

Point::Point() 
: Point(0, 0)
{

}

Those are the constructors you would want to use. This way you are calling the other constructor in what is called an initialiser list.

Your previous solutions just create a locale unnamed Point object, as calling Point() in a normal scope creates a Point object for you.

Secondly, you cannot use the this pointer safely within class construction, as the class has not been initialised fully yet, this means you will want to just refer to your types in the get and set methods by their names, not with this-> . So for example:

int Point::get_x() const
{
    return this->x_coord;
}

becomes

int Point::get_x() const
{
    return x_coord;
}

On a side note and for a little more info - that Point::Point(const Point& p) constructor is known as a copy constructor and is used when using the = operator. In the case of below:

Point a;
Point b = a;

The above code will call your Point::Point(const Point& p) constructor.

采用

Point::Point() : x_coord(0), y_coord(0) {}

Use a initializer list or have a common initialization function called from each constructor:

//initializer list
Point::Point() : x_coord(0), y_coord(0) {}
//common init function (call from constructors)
Point::init(int x, int y) { //perform initialization }

It may be better to use default values in the default constructor as

Point::Point ( int x = 0, int y = 0 )
    : x_coord ( x ), y_coord ( y )
{}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM