2017-10-12 6 views
1

Existe-t-il des méthodes en C++ que je puisse utiliser, telles que la surcharge ou la modélisation, qui me permettraient de passer des instances de classe en tant qu'argument à une fonction cmath? Par exemple, si j'avais une classe nommée "Point" (illustrée ci-dessous), est-il possible de réaliser l'opération std::abs(Point(-4, -9)) et de lui renvoyer Point(4, 9)?Comment puis-je effectuer une fonction cmath sur une instance de classe personnalisée?

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

Ou suis-je limité à l'utilisation des méthodes à base de classe qui me besoin d'appeler Point::abs(Point(-4, -9)) ou Point(-4, -9).abs()? Donc, en bref, puis-je augmenter la fonction cmath de toute façon pour accepter une instance de classe?

J'ai regardé autour et je ne trouve aucune information sur le sujet, cependant je suis assez nouveau en C++. Donc, j'apprécierais toute information sur la façon dont cela pourrait être fait, si cela peut être fait, et si une telle action est mal avisée, et si oui, pourquoi?

Merci d'avance.

Répondre

2

Jetez un oeil à this page de référence:

Pour le calcul des valeurs absolues, en cmath vous avez juste un tas de surcharges qui fonctionnent sur les types primitifs:

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

Étant donné que ces fonctions sont non modélisé, il n'y a aucun moyen de leur passer une classe Point et de récupérer une autre instance de Point. Ils peuvent uniquement recevoir un type primitif et renvoyer le même type.

Quelque chose comme ceci (semblable en termes de syntaxe seulement) pourrait seulement se produire, si votre classe de point était convertible en un de ces types primitifs. Par exemple. dans l'extrait suivant, j'ai défini la classe A, qui est implicitement convertible vers et depuis int, donc quand j'appelle abs avec une instance de A, il est automatiquement converti en int, passé à la surcharge appropriée de abs, et enfin le résultat est reconverti en 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(); 
} 

Mais c'est à peu près jusqu'où vous pouvez aller avec cette astuce que je pense ne couvre pas ce que vous voulez. Je crois que la meilleure approche dans votre cas est de créer une fonction d'utilité, qui fait ce que vous voulez. Je préfère opter pour une fonction gratuite, au lieu d'un membre statique, pour ne pas encombrer la classe avec des méthodes utilitaires inutiles, c'est-à-dire quelque chose comme ceci

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

Les deux approches que vous montrez sont des façons valides de le faire. Il n'y a aucun moyen d'utiliser std :: abs directement sur votre classe Point.

Une autre façon est de rendre votre fonction abs1 statique dans une fonction abs libre. Si sa déclaration est dans un fichier d'en-tête, elle surcharge essentiellement la fonction std :: abs. Pour l'implémenter en tant que fonction libre, vous devez implémenter des fonctions membres pour obtenir x et y ou faire de votre fonction libre un ami de votre classe Point.

1

Vous le feriez comme ça.

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