C++中的结构和操作员过载

Structures and Operator Overloading in C++

本文关键字:操作员 结构 C++      更新时间:2023-10-16
struct PT 
{   
  double x, y;  
  PT() {}  
  PT(double x, double y) : x(x), y(y) {}  
  PT(const PT &p) : x(p.x), y(p.y)    {}  
  PT operator + (const PT &p)  const { return PT(x+p.x, y+p.y); }  
  PT operator - (const PT &p)  const { return PT(x-p.x, y-p.y); }  
  PT operator * (double c)     const { return PT(x*c,   y*c  ); }  
  PT operator / (double c)     const { return PT(x/c,   y/c  ); }  
};

此代码片段来自 http://stanford.edu/~liszt90/acm/notebook.html#file8 .我无法理解这段代码.有人请解释一下.我知道这是运算符重载,但无法理解运算符重载的确切发生方式。

有人也可以解释这些台词吗:

PT() {}  
PT(double x, double y) : x(x), y(y) {}  
PT(const PT &p) : x(p.x), y(p.y)    {}

结构也有构造函数吗?

double x, y;  

声明组成类的两个局部类变量。

PT() {}  

默认构造函数。 允许您创建没有任何参数的 PT。
例如 --> PT myObj;

PT(double x, double y) : x(x), y(y) {}  

从两个双精度创建点的构造函数。
例如 --> PT myObj(3.5, 9.0);
声明后 --> PT(double x, double y) : x(x), y(y) {}
我们有初始化 .--> PT(Double x, double y) : x(x), y(y) {}
x(x)相当于this->x = x;
即使用构造函数参数"x"初始化类变量"x"。 他们给参数指定了与类变量相同的名称,这有点令人困惑。 一个更好的例子可能是:

    PT(double xInit, double yInit) 
    : x(xInit)
    , y(yInit) 
    {
    }  



    PT(const PT &p) : x(p.x), y(p.y)    {}  

复制构造函数以从另一个 PT 对象创建 PT 对象
例如 --> PT myOtherObj(myObj);

PT operator + (const PT &p)  const { return PT(x+p.x, y+p.y); }  
PT operator - (const PT &p)  const { return PT(x-p.x, y-p.y); }

加法和减法运算符得到两点的总和或差,以做第三个点。
例如 -->

    PT sumObj  = myObj + myOtherObj;
    PT diffObj = myObj - myOtherObj;




PT operator * (double c) const { return PT(x*c, y*c ); } PT operator / (double c) const { return PT(x/c, y/c ); }

乘法和除法运算符,用于将点乘以(或除以)一个常量。
例如 -->

    PT prodObj = myObj * 2.7;
    PT divObj  = myObj / 8.0;

4 行和第 5 行是构造函数,语法x(x)突出显示了一种调用成员变量构造函数的惯用方法(可以说是向下传递)。

请注意,形式参数不需要不同的标识符。从构造函数主体内部赋值需要不同的命名,因为形式参数"隐藏"了成员变量。即我们需要,例如

 PT(double x_, double y_) { x = x_; y = y_; }  

另请注意,这样我们不是调用成员 x 的构造函数,而是调用赋值运算符。POD 数据没有区别,但语法允许在类(如 PT )上使用任意的、用户定义的成员函数。

每当编译器遇到表单调用时

a + b;

它实际上调用

a.operator+(b)

如果该方法存在于 或 的类型中

operator+(a,b)

如果存在这样的自由函数。

运算符???语法只是说您当前正在重载所述运算符???(当然,对于任何有效的???)。

运算符重载是一个概念,其中通常的运算符如 + 、'- , '*、...对于结构/类也是"重载"的。通常,此工具仅适用于原始数据类型,如intdouble、....

struct PT中,运算符方法被简单地定义。一旦您声明了PT的对象并开始使用它,它就会启动。例如

PT pt1, pt2;
PT pt3 = pt1 + pt2;  // pt1.operator +() has instantiated

通过查看它的非成员版本,可能更容易理解运算符重载。如果要告诉编译器添加两个PT对象是什么意思,可以编写以下内容:

PT operator + (const PT& a, const PT& b)
{
    return PT(a.x + b.x, a.y + b.y);
}

上面的代码只是说,当编译器找到表达式a + b ab都是PT实例时,结果是由该函数计算的新PT实例。

您可以对其他一些运算符执行相同的操作,因此,您可以使您的类实例相对于普通数学的行为更加"自然"。

您拥有的代码是相同的,但以有点不自然的非对称形式编写,例如,您描述了当另一个对象添加到this对象时该怎么做。对于二进制数学运算符来说,这种方法看起来很奇怪,因为例如,加法的第一个或第二个操作数没有什么特别的,它们都处于相同的逻辑级别。然而,this概念的不对称性是C++DNA的一部分,你对此无能为力。从理论上讲,对于任何仅采用参数的方法来说,这都是一个糟糕的不对称性,但在实践中,即使使用这种方法,您仍然可以使用相当长的一段时间。

代码的其他部分是:

// Default constructor. Will create an object without any parameter
// and the x, y values will be uninitialized. This is generally a bad
// practice and you should avoid it unless there are very specific and
// measured performance reasons for doing that.
// Having a constructor accepting no parameters is sometimes necessary
// if you want for example to be able to put your instances in an std::vector
// and you may need to call .resize() on the vector. Even if you will always
// just shrink the vector the compiler will require anyway a default
// constructor because there's no shrink-only call on vectors and any
// resize operation is assumed to be potentially growing the size.
PT() {}
// Copy constructor. This is totally unneeded... when you don't
// put a copy constructor in a class the C++ compiler will automatically
// generate exactly this code (i.e. a constructor that will copy-construct
// all members). In general this may be or may not be the right thing
// depending on the class, but in this case is exactly what you want
// and there was no need for this code.
// As a general rule if you see a copy constructor, an assignment operator
// or a destructor but you don't see all three of them in a class then
// most probably there's something wrong. It's difficult to think to
// a real use case in which you need some of them but not all three of
// them... in this case for example the mistake is that this code could
// and should have been omitted.
PT(const PT &p) : x(p.x), y(p.y) {}