简体   繁体   English

在C ++中键入别名

[英]Type aliases in C++

I have a class Point and a class Rect . 我有一个Point类和一个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). 我想为Rect有两个构造函数:一个带有Point和一个尺寸(宽度,高度)的构造函数,一个带有两个Point(左上,右下)的构造函数。 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: 现在事实证明Point也可以看作是一个维度,因此与其创建Dimension类,不如我想使用Point ,基本上是这样的:

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 ? 所以问题是:编译器是否会在PointDimension之间产生区别? I tried it, the message ist "call of overloaded Rect(Point, Point) is ambiguous.". 我尝试过,消息ist“重载Rect(Point,Point)的调用是模棱两可的”。

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). 坐标可以在笛卡尔系统(x,y)或GPS坐标(lon,lat)中。 It's perfectly ok for me to call the components x0 and x1 so I want to use only one class. 对我来说,调用组件x0x1所以我只想使用一个类。

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"? 但是,答案是否还会是“两堂课”?

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 . 使用这种方法,您可以在类模板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. 许多C ++库(例如Boost)都采用了最后一种方法。

You should make Dimension a different type. 您应该使Dimension为其他类型。 Yes, a Point can be used to specify a dimension, but it doesn't mean that it makes sense to use the same type. 是的,可以使用Point来指定尺寸,但这并不意味着使用相同的类型是有意义的。

The compiler makes no difference between Point and Dimension . 编译器在PointDimension之间没有区别。

You have to create another class for Dimension . 您必须为Dimension创建另一个类。 Just as a hint, you can use w and h instead of x and y for its members. 只是提示,您可以使用wh代替xy作为其成员。

If point and dimension don't have identical behaviour, then your typedef is a logic error. 如果pointdimension行为不同,则您的typedef是逻辑错误。 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. 这与std::size_tvoid*完全不同-它们对于底层硬件来说都是相同的位数,但是语言的类型系统赋予它们完全不同的含义。

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>);

一种快速的解决方案是,您可以有一个构造函数,并弄清楚逻辑内部提供的类

Although Dimension and Point are similar in that they can both be implemented as a pair of numbers, their behaviour isn't the same, eg Dimension would probably have member functions like height() and width() whereas Point might have x() and y(). 尽管Dimension和Point是相似的,因为它们都可以实现为一对数字,但是它们的行为并不相同,例如Dimension可能具有height()和width()之类的成员函数,而Point可能具有x()和Y()。 So you shouldn't make them the same, but have different classes for each. 因此,您不应该使它们相同,但是每个类具有不同的类。

You can try making Dimension inherit from Point Instead of be a typedef: 您可以尝试使Dimension从Point继承,而不是成为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. 这具有允许编译器为那些类型生成多态代码的额外好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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