Jak uniknąć niejawnego rzutowania?

0

Witam.

klasa Vec (robiąca za vektor) posiada 2 przeciążenia operatora *:

	Vec operator* (double a)const
	{
		Vec v = (*this);
		for (int i = 0; i < v.n; i++)
		{
			v[i] *= a;
		}

		return v;
	}

	double operator* (const Vec& u)const
	{
		double l = 0;
		
		for(int i = 0; i < (u.n < this->n ? u.n : this->n); i++)
		{
			l += u[i] * (*this)[i];
		}
		
		return l;
	}

W momencie, gdy w mainie wywołuję instrukcję:

	cout << (wektory[0] * 2)[0]

(gdzie 'wektory' to tablica obiektów klasy Vec), kompilator wyrzuca mi błąd, że nie wie którego operatora użyć (mimo że jest tylko jeden taki, w którym po lewej stoi Vec a po prawej double).

Wiem czemu tak się dzieje: w klasie Vec mam też przeciążenie rzutowania na double:

	operator double()const
	{
		double s = 0;
		for (int i = 0; i < this->n; i++)
		{
			s += (*this).A[i];
		}

		return sqrt(s);
	} 

po prostu kompilator ma drugą opcję - niejawne skonwertowanie wektora na double, a następnie pomnożenie doubli. Chcę zachować wszystkie powyższe przeciążenia, i chcę uniknąć tego niejawnego rzutowania. Jak mam to zrobić?

Jeszcze jedno: jak mam sobie to mnożenie przez liczbę:

 	Vec operator* (double a)const
	{
		Vec v = (*this);
		for (int i = 0; i < v.n; i++)
		{
			v[i] *= a;
		}

		return v;
	}

to program podczas zmieniania v, zmienia mi też to co stoi w this, a przecież specjalnie zamiast robić v wskaźnikiem na Vec, i ustawiać na to, na co pokazuje this, to wyłuskałem wartości z this, i wstawiam je przez wartość do v...

Dobra, to drugie nieważne, po prostu domyślny konstruktor kopiujący był źle zrobiony. Ponawiam za to pytanie z pierwszego posta.

0

Trochę tego nie rozumiem:

cout << (wektory[0] * 2)[0]

Jeżeli najpierw skonwertujemy wektory[0] (zakładam, że wektory to Vec[]) do double i pomnożymy razy 2, to wyjdzie nam wartość typu double - więc tak właściwie po co tam operator []?
Jeżeli natomiast wywołamy operator* to z mnożenia dostaniemy obiekt Vec. Czy Vec ma przeładowany operator[]? Jeżeli nie, to to również nie ma sensu.
A co, jeżeli zamiast konwertować Vec do double użyłbyś konstruktora Vec(double)? Wtedy mógłbyś zrobić go explicit i mieć osobny operator* dla Vec i double.

0
Azrael_Valedhel napisał(a)

Trochę tego nie rozumiem:

cout << (wektory[0] * 2)[0]

Jeżeli najpierw skonwertujemy wektory[0] (zakładam, że wektory to Vec[]) do double i pomnożymy razy 2, to wyjdzie nam wartość typu double - więc tak właściwie po co tam operator []?
Jeżeli natomiast wywołamy operator* to z mnożenia dostaniemy obiekt Vec. Czy Vec ma przeładowany operator[]? Jeżeli nie, to to również nie ma sensu.
A co, jeżeli zamiast konwertować Vec do double użyłbyś konstruktora Vec(double)? Wtedy mógłbyś zrobić go explicit i mieć osobny operator* dla Vec i double.

Po co operator [0] na końcu? bo nie chodzi o konwersję. Chcę, aby w tym wypadku pomnożono wektor przez skalar, wynikiem ma być wektor. I tak, zapomniałem napisać, Vec ma przeładowany operator[], ---> v[n] zwróci wtedy tak naprawdę v.A[n] (gdzie v - Vec, A - double* (tablica współrzędnych wektora)), więc chcę wypisać na ekran pierwszą współrzędną wektora będącego wynikiem iloczyny wektora przez liczbę.

Konstruktor Vec(double) jest, istnieje. Ale konwersja Vec do double musi być, bo takie jest widzimisię prowadzącego zajęcia... -_-'.

0

Hm, taki przykład wymodziłem:

#include <iostream>

class Vec {
public:
    Vec(double) {}
    Vec() {}
    
    Vec operator*(double) { return *this; }
    double operator*(const Vec& ) { return 10.5; }
    explicit operator double() { return 5.5; } // C++0x
    
};

std::ostream& operator<<(std::ostream& out, const Vec& ) {
    return out << "Vec";
}

int main() {
    using namespace std;

    Vec v;
    cout << ( v * 2 ) << '\n';
    
    return 0;
}

To się skompiluje i działa tak jak powinno, ale jest jeden haczyk. Bez ostrzeżeń skompiluje się tylko w trybie C++0x (używając g++ 5.4.2 -std=c++0x ). :)

Bez tego explicit dostaję:

cpp_main.cpp: In function 'int main()':
cpp_main.cpp:22:19: error: ambiguous overload for 'operator*' in 'v * 2'
cpp_main.cpp:22:19: note: candidates are: operator*(double, int) <built-in>
cpp_main.cpp:8:9: note:                 Vec Vec::operator*(double)
cpp_main.cpp:9:12: note:                 double Vec::operator*(const Vec&)

Wystarczy jednak zmienić 2 na 2.0 (w cout << ( v * 2 ) << '\n';) żeby się to skompilowało. Czy to w jakiś sposób Ci pomoże?

0

Hmmm dodałem explicit (a najpierw doczytałem o tym i wywiedziałem się co robi ;) ) i oto co mi powiedział kompilator (przy linijce "explicit operator double();" w pliku Vec.h

error C2071: 'Vec::operator double' : illegal storage class

0

W tym przypadku w ogóle bym zrezygnował z rzutowania na double. Według mnie zwracanie długości wektora jest nienaturalne. Daj po prostu funkcje length() i nie będzie problemów. Rzadko kiedy jest potrzebna długość wektora, a szczególnie przez takie rzutowanie. Jeżeli ktoś zobaczy kod używający tej klasy, to nie będzie miał pojęcia o co chodzi bez wyraźnych komentarzy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1