Reputation: 7344
I have a class Point
and a class Rect
. I want to have two constructors for the Rect
: One with a Point
and a dimension (width, height) and one with two Points (top left, bottom right). Now it turns out that Point
also can be seen as a dimension, so instead of creating a Dimension
class I want to use my Point
, basically like this:
class Point{...};
typedef Dimension Point;
class Rect{
public:
Rect(Point, Point);
Rect(Point, Dimension);
}
So the question is: Does the compiler make a difference between Point
and Dimension
? I tried it, the message ist "call of overloaded Rect(Point, Point) is ambiguous.".
How should I do that? Preferably without inheritance :)
EDIT
I understood now that it's the same to the compiler. But there is another scenario wher I need that.
I have a Point. The coordinates can be in a carthesian system (x, y) or GPS coordinates (lon, lat). It's perfectly ok for me to call the components x0
and x1
so I want to use only one class.
Now I want to calculate the distance between the two points and my idea is as follows:
typedef PointLonLat Point;
typedef PointXY Point;
double distance(PointLonLat, PointLonLat);
double distance(PointXY, PointXY);
PointLonLat p1(10, 10);
PointLonLat p2(11, 11);
double dist = distance(p1, p2); // the correct implementation is used
I know it doesn't work like that. But would the answer to that also be "make two classes"?
Upvotes: 2
Views: 197
Reputation: 13192
If point
and dimension
don't have identical behaviour, then your typedef
is a logic error. If they do, then you don't need two constructors.
In response to your edit
For the example you've provided, what you have is two classes that store the same amount of data but have different behaviour. It's analagous to std::size_t
and void*
- they're both the same number of bits to the underlying hardware, but the language's type system gives them totally different meanings.
Your example could be solved by using two different classes, or by using a template class to avoid duplication like this:
enum CoordinateSystem {
Geographic,
Cartesian
};
template<CoordinateSystem C>
struct Point {
double x,y;
};
double distance(Point<Cartesian>, Point<Cartesian>);
double distance(Point<Geographic>, Point<Geographic>);
Upvotes: 1
Reputation: 361762
All typedefs are same for compiler.
You could do this instead:
//class template to be used to generate different class types!
template<int>
class Type{ /*...*/ };
//instantiate different class types, each with different template argument
typedef Type<0> Point;
typedef Type<1> Dimension;
typedef Type<2> Size;
class Rect{
public:
Rect(Point, Point);
Rect(Point, Dimension); //its a different constructor!
};
Using this approach, you create different types out of the class template Type
.
Instead of integer literals, you could use named enum as:
enum TypeArg
{
PointArg,
DimensionArg,
SizeArg
};
template<TypeArg>
class Type{ /*...*/ };
typedef Type<PointArg> Point;
typedef Type<DimensionArg> Dimension;
typedef Type<SizeArg> Size;
Or even better use empty classes as:
//empty classes
struct PointArg{};
struct DimensionArg{};
struct SizeArg{};
template<typename T>
class Type{ /*...*/ };
typedef Type<PointArg> Point;
typedef Type<DimensionArg> Dimension;
typedef Type<SizeArg> Size;
This last approach is adopted by many C++ libraries, such as Boost.
Upvotes: 3
Reputation: 144
You can try making Dimension inherit from Point Instead of be a typedef:
class Dimension : public Point {}
Also, it is inefficient to pass the object types as copies; pass them as constant references instead. That has the additional benefit of allowing the compiler to generate polymorphic code for those types.
Upvotes: 0
Reputation: 3266
Although Dimension and Point are similar in that they can both be implemented as a pair of numbers, their behaviour isn't the same, e.g. Dimension would probably have member functions like height() and width() whereas Point might have x() and y(). So you shouldn't make them the same, but have different classes for each.
Upvotes: 0
Reputation: 37477
The compiler makes no difference between Point
and Dimension
.
You have to create another class for Dimension
. Just as a hint, you can use w
and h
instead of x
and y
for its members.
Upvotes: 1
Reputation: 2510
One quick solutions is that you can have one constructor and figure out the class that is being provided inside it's logic
Upvotes: 0
Reputation: 64444
You should make Dimension
a different type. Yes, a Point
can be used to specify a dimension, but it doesn't mean that it makes sense to use the same type.
Upvotes: 2