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

时间:2017-10-12 20:11:42

标签: c++ class overloading templating cmath

我可以使用C ++中的任何方法,例如重载或模板,这样我可以将类实例作为参数传递给cmath函数吗?例如,如果我有一个名为“Point”的类(如下所示),是否有任何方法可以执行操作std::abs(Point(-4, -9))并让它返回Point(4, 9)?< / p>

#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()的基于类的方法?所以简而言之,我可以在任何方面扩充cmath函数来接受类实例吗?

我浏览了一下,找不到有关该主题的任何信息,但我对C ++很陌生。所以,我会感谢有关如何做到这一点的任何信息,是否可以做到,以及这样的行动是否是不明智的,如果是,为什么?

提前致谢。

3 个答案:

答案 0 :(得分:2)

查看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类并返回Point的另一个实例。它们只能接收基本类型,并返回相同的类型。

如果你的Point类可以转换为其中一种原始类型,那么这样的东西(仅在语法方面类似)才会发生。例如。在下面的代码片段中,我定义了类A,它可以隐式转换为int和int,因此当我用一个A实例调用abs时,它会自动转换为int,传递给{{1的适当重载最后将结果转换回A。

abs

但这就是你可以用这个技巧走多远,我认为这并不能涵盖你想要的东西。我认为在你的情况下最好的方法是创建一些实用功能,做你想要的。我宁愿选择一个免费的函数,而不是一个静态成员,不要用不必要的实用方法乱丢这个类,就像这样的东西

#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();
}

答案 1 :(得分:1)

您展示的两种方法是有效的方法。没有办法直接在你的Point类上使用std :: abs。

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

答案 2 :(得分:1)

你会这样做。

#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;
}