2012-02-06 15 views
7

Mam trudny czas tworzących pytanie, co staram się zapytać więc podam przykład:Podstawowe operator przeciążenia składni w C++

powiedzieć, że pracujesz na systemie 3D, gdzie mamy zdefiniowano klasę wektorową, Vec3. Przeciążamy niektóre operatory arytmetyczne dla oczywistych rezonansów. Pośród nich przeciążamy operator *, aby zwracał iloczyn dwójkowy dwóch wektorów. Teraz nasz kod powinien wyglądać następująco:

class Vec3{ 
private: 
    float x, y, z; 
public: 
    float operator*(const Vec3&) const; //dot product 
. 
. 
. 

teraz powiedzieć, że chcemy, aby móc skalować naszą wektor za pomocą operatora * z czymś, powiedzmy pływak. Można tego dokonać przez oświadczenie następujące:

Vec3 operator*(const float) const; 
    friend Vec3 operator*(const float, const Vec3&); 

to yeilds dwa przeciążeń i Zastanawiam się, czy istnieje sposób, aby zrobić to z tylko jednym, czyli powiedzieć deklarujemy to zamiast powyższych dwóch liniach:

friend Vec3 operator*(const Vec3&, const Vec3&); 

a następnie dodać wartości domyślne dla ctor vec3 do obsługi konwersja z pływaka.

Ten ostatni przykład będzie pracować dla:

Vec3 someVec3 = 1.0 * otherVec3; //through friend Vec3 operator*(const float, const Vec3&) 

jednak nie to:

Vec3 someVec3 = otherVec3 * 1.0; 

jak kompilator nie będzie wiedział, który z nich korzystać:

friend Vec3 operator*(const float, const Vec3&); //the one we want to use 
or 
    float operator*(const Vec3&) const; //the one for the dot product 

Wszelkie sugestie?

Dziękujemy!

+3

Co jest nie tak z dwoma przeciążeniami? Jak podkreślasz, dość nieprzyjemna dwuznaczność jest tworzona, gdy próbujesz to uprościć ... –

+2

Jedyną rzeczą, którą zrobiłbym inaczej, jest uczynienie obu wersji skalarnych funkcji mnożących się znajomych, zamiast jednego będącego członkiem, tak, że kod będzie mają taką samą symetrię jak sama operacja. –

+0

Byłoby nieefektywne skonstruowanie wektora tylko po to, aby przekazać float. Byłoby to nieefektywne działanie w czasie wykonywania, ale można było nałożyć dodatkową funkcję przeciążenia. – QuentinUK

Odpowiedz

5

W tym przypadku chciałbym początkowo odradzają przeciążenia operatora, bo jak się użytkownicy wiedzieć czy * reprezentuje kropkę lub produkt cross (oba są rozsądne znaczeń w zależności od przewidywanego zastosowania klienta). Proponuję po prostu nie wspierać operator* i robić to z członkami dot, cross i scale. Wtedy nie musisz martwić się o wiele przeciążeń i dla użytkowników jest jasne, co otrzymują.

Jeśli jednak chcesz pracować z operatorami, nie ma problemu z dwoma przeciążeniami. Utworzenie atrapa Vec3 do skalowania jest nie tylko semantycznie niepoprawne, ale doda niewielką ilość niepotrzebnego narzutu.

1

Nie ma nic złego w kilka przeciążeń, zwłaszcza jeżeli nie mogą one być łatwo realizowane pod względem siebie:

Vec3 operator*(const float scale, const Vec3& vec) 
{ return vec * scale; } 

Trudno jest dostać to prostsze niż to!

2

Boost.Operators może wykonać większość pracy z płytą kotła. Np .:

class Vec3 
    : boost::multipliable2<Vec3, float> 
{ 
public: 
    // ... 

    Vec3 operator*=(float); 
    // Vec3 operator*(Vec3, const float&) and 
    // Vec3 operator*(const float&, Vec3) auto-generated 
    // by multipliable. 
};