如何在自定义 class 实例上执行 cmath 函数?

How can I perform a cmath function on a custom class instance?

C++ 中是否有任何我可以使用的方法(例如重载或模板化)允许我将 class 个实例作为参数传递给 cmath 函数?例如,如果我有一个名为 “Point” 的 class(如下所示),有什么方法可以执行操作 std::abs(Point(-4, -9)) 并让它 return Point(4, 9)?

#include <iostream>
#include <cmath>

class Point{
    private:
        double x, y;

    public:
        Point(double x, double y) {
            this->x = x;
            this->y = y;
        }

        // Approach 1 that I would like to avoid 
        static Point abs1(const Point &p1) {
            return Point(std::abs(p1.x), std::abs(p1.y));
        }

        // Approach 2 that I would like to avoid 
        Point abs2(void) {
            return Point(std::abs(x), std::abs(y));
        }
};

int main()
{
    Point pt1(-4.0, -9.0), pt2;

    pt2 = std::abs(pt1) // <-- What I would like to be able to do

    pt2 = Point::abs1(point_d); // <-- Function call 1 that I would like to avoid
    pt2 = point_d.abs2(); // <-- Function call 2 that I would like to avoid

    return 0;
}

或者我是否仅限于使用需要调用 Point::abs(Point(-4, -9))Point(-4, -9).abs() 的基于 class 的方法?所以简而言之,我是否可以增加 cmath 函数以接受 class 实例?

我环顾四周,找不到关于这个主题的任何信息,但我对 C++ 还是很陌生。因此,如果能提供有关如何执行此操作、是否可以执行此操作以及此类操作是否不明智以及如果是这样的原因的任何信息,我将不胜感激?

提前致谢。

您展示的两种方法都是有效的方法。没有办法直接在你的点 class.

上使用 std::abs

另一种方法是将静态 abs1 函数转换为自由 abs 函数。如果它的声明在头文件中,它实际上会重载 std::abs 函数。为了将其实现为自由函数,您需要实现成员函数以获取 x 和 y 或使您的自由函数成为您的朋友 Point class.

你会这样做。

#include <iostream>
#include <cmath>

class Point{
        double x, y;

    public:
        Point(double x, double y)
        : x(x), y(y)
        {
        }

    friend Point abs(const Point &p1) {
        return Point(std::abs(p1.x), std::abs(p1.y));
    }
};


int main()
{
    using std::abs;

    Point pt1(-4.0, -9.0);
    double x = 5.5;

    // this will work even if Point is in its own namespace
    // because of ADL
    Point pt2 = abs(pt1);    

    // this works because for this function, we have pulled
    // std::abs into the global namespace
    double y = abs(x);

    return 0;
}

查看 this 参考页:

为了计算绝对值,在 cmath 中你只有一堆对原始类型进行操作的重载:

  int abs(int j);
  long int abs(long int j);
  long long int abs(long long int j);
  float abs(float j);
  double abs(double j);
  long double abs(long double j);

由于这些函数不是模板化的,因此您无法将 Point class 传递给它们并取回 Point 的另一个实例。他们只能接收一个原始类型,并且return相同的类型。

只有当您的 Point class 可转换为这些原始类型之一时,才会发生类似这样的事情(仅在语法方面相似)。例如。在下面的代码片段中,我定义了 class A,它可以隐式转换为 int,因此当我使用 A 的实例调用 abs 时,它会自动转换为 int,传递给适当的重载abs,最后将结果转换回A.

#include <cmath>
#include <iostream>


class A
{
public:
    A(int x_)    // implicit conversion from int
    : x(x_)
    {}

    operator int()
    {
        return x; // implicit conversion to int
    }
private:

    int x;
};


int Foo(int x)
{
    return x * 2;
}

int main()
{
    A a1(-2);
    A a2 = Foo(a1);
    A a3 = std::abs(a1);

    std::cout << "a2: " << a2 << "\n";
    std::cout << "a3: " << a3 << "\n";

    getchar();
}

但这几乎就是你可以使用这个技巧的程度,我认为它没有涵盖你想要的。我相信在你的情况下最好的方法是创建一些效用函数,它可以做你想要的。我宁愿选择一个自由函数,而不是一个静态成员,不要用不必要的实用方法乱扔 class,即像这样的东西

namespace PointUtils
{
    Point abs(const Point& p);
}