Czytałem, że przeciążony operator zadeklarowany jako funkcja członkowska jest asymetryczny, ponieważ może mieć tylko jeden parametr, a drugim parametrem przekazywanym automatycznie jest this
wskaźnik. Nie ma więc standardu, aby je porównać. Z drugiej strony przeciążony operator zadeklarowany jako a friend
jest symetryczny, ponieważ przekazujemy dwa argumenty tego samego typu, dzięki czemu można je porównać.
Moje pytanie jest takie, że jeśli nadal mogę porównać wartość l wskaźnika z referencją, dlaczego preferowani są przyjaciele? (użycie wersji asymetrycznej daje takie same wyniki, jak wersja symetryczna) Dlaczego algorytmy STL używają tylko wersji symetrycznych?
Odpowiedzi:
Jeśli zdefiniujesz funkcję przeciążoną przez operatora jako funkcję składową, kompilator tłumaczy wyrażenia, takie jak
s1 + s2
nas1.operator+(s2)
. Oznacza to, że przeciążona przez operatora funkcja członkowska jest wywoływana na pierwszym operandzie. Tak działają funkcje członkowskie!Ale co, jeśli pierwszy operand nie jest klasą? Istnieje poważny problem, jeśli chcemy przeciążyć operator, którego pierwszy operand nie jest typem klasy
double
. Więc nie możesz tak pisać10.0 + s2
. Możesz jednak napisać funkcję składową przeciążoną przez operatora dla wyrażeń, takich jaks1 + 10.0
.Aby rozwiązać ten problem z porządkowaniem , definiujemy funkcję przeciążoną przez operatora jako
friend
JEŚLI potrzebuje dostępu doprivate
członków. Zrób tofriend
TYLKO wtedy, gdy potrzebuje dostępu do prywatnych członków. W przeciwnym razie po prostu uczyń to nieprzyjazną funkcją niebędącą członkiem, aby poprawić hermetyzację!Przeczytaj to:
Niewielki problem z porządkiem w operandach. Jak funkcje niebędące składnikami
poprawiają enkapsulację
źródło
friend
tylko wtedy, gdy potrzebuje dostępu do prywatnych członków… i kiedy nie masz / nie znudzisz się pisaniem akcesorów, prawda?”a/b
.friend
jest ich implementacja w kategoriach operatorów przypisania operacji (które prawie na pewno będą członkami publicznymi). Na przykład możesz zdefiniowaćT T::operator+=(const T &rhs)
jako członka, a następnie zdefiniować osobę niebędącą członkiemT operator(T lhs, const T &rhs)
jakoreturn lhs += rhs;
. Funkcja niebędąca składową powinna być zdefiniowana w tej samej przestrzeni nazw, co klasa.Niekoniecznie jest to rozróżnienie między
friend
przeciążeniami operatorów i przeciążeniami operatorów funkcji składowych, ponieważ występuje między przeciążeniami operatorów globalnych a przeciążeniami operatorów funkcji składowych.Jednym z powodów, dla których warto preferować przeciążenie operatora globalnego , jest zezwolenie na wyrażenia, w których typ klasy pojawia się po prawej stronie operatora binarnego. Na przykład:
Działa to tylko wtedy, gdy istnieje przeciążenie operatora globalnego dla
Zauważ, że przeciążenie operatora globalnego niekoniecznie musi być
friend
funkcją. Jest to konieczne tylko wtedy, gdy potrzebuje dostępu do prywatnych członkówFoo
, ale nie zawsze tak jest.Niezależnie od tego, gdyby
Foo
tylko miał przeciążenie operatora funkcji składowej, na przykład:... wtedy moglibyśmy mieć tylko wyrażenia, w których
Foo
wystąpienie pojawia się po lewej stronie operatora plus.źródło