简体   繁体   中英

How to workaround “redefinition of default parameter” in class constructor

Consider the following example:

class Rectangle{
    Rectangle(int x, int y, int width, int height);
    Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);    
};

A Rectangle object may be built giving (x,y) coordinates plus width and height or giving top left points pair and bottom right points pair.

While this is correct from an object oriented point of view, this is not from a compiler point of view, returning the error "member function already defined or declared"

While I normally fix this condition easily in case of member function, simply changing the name according to what it does, this is not possible for constructors.

What is the simpler and correct way to workaround this issue keeping both the way to construct the object?

Another possible solution (other than the pair suggested by @VladfromMoscow) is a static method to perform construction. This lets you give them distinct names, since their argument lists are so similar. Thisi is called the Named Constructor Idiom

class Rectangle
{
 public:
   static Rectangle createRectangle(int x, int y, int width, int height) 
   {
      return Rectangle(x,y,width,height);
   }
   static Rectangle createRectangleCorners(int x1, int y1, int x2, int y2) 
   {
      return Rectangle(x1,y1,x2-x1, y2-y1); 
   }
 private:
   // Doesn't have to be private, but this forces users to use the above 
   // constructors
   Rectangle(int x, int y, int width, int height);
}

You wrote already yourself

top left points pair and bottom right points pair

So what you need is to define class Point and use this type in the constructor declaration.

Otherwise the constructors are declared like

class Rectangle{
    Rectangle(int, int, int, int);
    Rectangle(int, int, int, int);    
};

As you see these declarations do not make sense even if you will write multiline comments.:)

Another approach is to declare the first constructor like

class Rectangle{
    Rectangle(int x, int y, unsigned int width, unsigned int height);
    Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);    
};

However this approach is unsafe because each integer literal specified as the third or fourth argument must be casted.

Instead of the class Point you could use standard class std::pair . For example

#include <utility>

//...

class Rectangle{
    Rectangle(int x, int y, int width, int height);
    Rectangle( const std::pair<int, int> &topLeft, const std::pair<int, int> &bottomRight);    
};

Another way on how to solve this problem is by using Tag dispatching :

Instead of using methods with different names, give them a new parameter, eg,

 struct useCorners {}; struct useDimension {}; class Rectangle { Rectangle(useCorners, int topLeft, int topRight, int bottomLeft, int bottomRight) { ... } Rectangle(useDimension, int topLeft, int topRight, int width, int height) { ... } }; 

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