Java가 왜 연산자 오버로드를 제공하지 않습니까?


406

C ++에서 Java로 올 때 대답이 분명하지 않은 질문은 Java에 연산자 오버로드가 포함되지 않은 이유는 무엇입니까?

아닌가 Complex a, b, c; a = b + c;보다 훨씬 간단 Complex a, b, c; a = b.add(c);?

연산자 오버로드를 허용 하지 않는 유효한 인수가 알려진 이유가 있습니까? 그 이유는 임의적입니까, 아니면 시간을 잃었습니까?



1
@ zzzz, 그 기사를 읽는 데 어려움이 있습니다. 이 언어는 자동 번역 되었습니까, 아니면 영어는 작가의 제 2 언어입니까? 나는 여기서 논의가 훨씬 깨끗하다는 것을 알았다.

25
이것을 건설적이지 않은 것으로 마무리 짓는 사람들의 더미에,이 질문은 내가 SO에서 본 가장 건설적인 대화 중 일부를 산출했습니다. 아마도 programmers.stackexchange.com 에 대한 더 나은 후보 일지 모르지만 SO가 더 넓은 주제를 지나치게 무시하고 있다고 생각되는 경우가 있습니다.

단지 정신적으로 삽입이 쉽게 @NoNaMe 및 - 실종 artlcles하는 사람이 영어를 모국어 스피커 나 프로그래머가 (중 아니라고 죽은 경품의 경우, 또는이 사람처럼, 모두 :) 기사를 삭제할 수 있습니다 이유 프로그래머는 할 수 있다는 것입니다 제공된 공간에서 주석을 더 짧고 쉽게 만들 수 있습니다. 거기서부터 익숙해집니다. 내 문제는 레이아웃과 관련이 있습니다. 어쨌든 나는 항상 Google 검색에서 해당 사이트를 방문하고 있습니다. 운 좋게도 페이지를 읽기 어려운 형식으로 멋지게 수정하는 Clearly 라는 훌륭한 크롬 확장 프로그램이 있습니다.
ycomp

1
OP가 첫 번째 답변을 수락 한 이유 및 방법을 모르겠습니다. @ stackoverflow.com/users/14089/paercebal에 의해 작성된 답변 이 우수합니다. 받아 들여야합니다.
소멸자

답변:


13

에서 참조하는 객체의 이전 값을 덮어 쓰려면 a멤버 함수를 호출해야합니다.

Complex a, b, c;
// ...
a = b.add(c);

C ++에서이 표현식은 컴파일러에게 스택에 3 개의 객체를 만들고 추가를 수행 하고 결과 값을 임시 객체에서 기존 객체로 복사 하도록 지시 합니다 a.

그러나 Java에서는 operator=참조 유형에 대한 값 복사를 수행하지 않으며 사용자는 값 유형이 아닌 새 참조 유형 만 작성할 수 있습니다. 따라서이라는 사용자 정의 유형의 Complex경우 할당은 기존 값에 대한 참조를 복사하는 것을 의미합니다.

대신 고려하십시오 :

b.set(1, 0); // initialize to real number '1'
a = b; 
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail

C ++에서는 값이 복사되므로 비교 결과가 동일하지 않습니다. 자바에서 operator=수행 그래서, 복사를 참조 a하고 b현재 동일한 값을 참조한다. 결과적으로 객체는 자신과 동일하게 비교되므로 비교는 '동일'을 생성합니다.

사본과 참조의 차이점은 운영자 과부하의 혼란을 추가합니다. @Sebastian이 언급했듯이 Java와 C #은 모두 값과 참조 평등을 개별적으로 operator+처리해야합니다. 값과 객체를 처리 할 가능성이 있지만 operator=참조를 처리하기 위해 이미 구현되었습니다.

C ++에서는 한 번에 한 종류의 비교 만 처리해야하므로 혼동이 줄어 듭니다. 예를 들어,에 Complex, operator=그리고 operator==두 값 작업입니다 - 값을 복사하여 각각 값을 비교.


6
정말 간단합니다 ... 그냥 파이썬처럼하고 과부하 할당이 없습니다.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

225
이 답변은 질문에 전혀 대답하지 않습니다. 당신은 단순히 자바의 등호 사용을 사용하고 있습니다. 만약 b + C가 새로운 Complex를 반환한다면, a = b + c는 완벽하게 유효 할 것입니다. a를 수정하려는 경우에도 a.set (b + c)는 읽기가 훨씬 간단합니다. 특히 산술이 사소한 것 이상일 때 : a.set ((a b + b c) / 5) 또는 a = a.multiply (b) .add (b.multiply (c)). divide (5). 당신의 선택 ..
BT

24
또는 아마도 .. 당신의 선택이 아닐 수도 있습니다.
BT

9
C ++에서 Expression Templates는 추가 사본의 문제를 해결합니다. 거의 모든 주요 산술 라이브러리가 바로이 기술을 사용합니다. 또한 a = b + c는 a.foo (b.bar (c))의 구문 설탕이므로 질문의 초기 관찰 사항 이므로이 문제를 다루지 않습니다.
Kaz Dragon

18
이것은 질문에 대한 답변이 아닙니다. 이것은 Java와 C ++의 특정 차이점에 대한 누군가의 추측입니다.
SChepurin

804

연산자 오버로드에 대해 불평하는 게시물이 많이 있습니다.

나는 "운영자 과부하"개념을 명확히해야한다고 생각하여이 개념에 대한 대안적인 견해를 제시했다.

코드 난독 화?

이 주장은 잘못된 것입니다.

모든 언어에서 난독 처리가 가능합니다 ...

연산자 오버로드를 통해 C ++ 에서처럼 함수 / 메소드를 통해 C 또는 Java로 코드를 난독 처리하는 것이 쉽습니다.

// C++
T operator + (const T & a, const T & b) // add ?
{
   T c ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

// Java
static T add (T a, T b) // add ?
{
   T c = new T() ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

/* C */
T add (T a, T b) /* add ? */
{
   T c ;
   c.value = a.value - b.value ; /* subtract !!! */
   return c ;
}

... Java의 표준 인터페이스에서도

또 다른 예를 들어, 자바로 Cloneable인터페이스 를 보자 :

이 인터페이스를 구현하는 객체를 복제해야합니다. 그러나 당신은 거짓말을 할 수 있습니다. 그리고 다른 객체를 만듭니다. 실제로이 인터페이스는 너무 약해서 재미를 위해 다른 유형의 객체를 모두 반환 할 수 있습니다.

class MySincereHandShake implements Cloneable
{
    public Object clone()
    {
       return new MyVengefulKickInYourHead() ;
    }
}

애즈 Cloneable인터페이스 남용 될 수 / 난독, 이는 C ++ 연산자 오버로딩이 있어야하는데 동일한 이유로 금지되어야 하는가?

우리 toString()MyComplexNumber클래스 의 메소드를 오버로드하여 문자열 화 된 시간을 반환하도록 할 수 있습니다. toString()과부하도 금지 해야합니까 ? 우리 MyComplexNumber.equals는 임의의 값을 반환하고 피연산자 등을 수정하도록 방해 할 수 있습니다.

Java에서 C ++ 또는 다른 언어와 마찬가지로 프로그래머는 코드를 작성할 때 최소한의 의미를 존중해야합니다. 즉 add, 추가 하는 기능과 Cloneable복제하는 구현 방법 및 ++증분보다 연산자를 구현 해야합니다 .

어쨌든 뭐가 난독 해?

이제 원시 Java 메소드를 통해서도 코드가 파괴 될 수 있음을 알았으므로 C ++에서 연산자 오버로드의 실제 사용에 대해 스스로에게 물어볼 수 있습니까?

명확하고 자연스러운 표기법 : 메서드와 연산자 오버로딩?

Java와 C ++의 "동일한"코드를 아래에서 비교하여 어떤 코딩 스타일이 더 명확한 지 알 수 있습니다.

자연 비교 :

// C++ comparison for built-ins and user-defined types
bool    isEqual          = A == B ;
bool    isNotEqual       = A != B ;
bool    isLesser         = A <  B ;
bool    isLesserOrEqual  = A <= B ;

// Java comparison for user-defined types
boolean isEqual          = A.equals(B) ;
boolean isNotEqual       = ! A.equals(B) ;
boolean isLesser         = A.comparesTo(B) < 0 ;
boolean isLesserOrEqual  = A.comparesTo(B) <= 0 ;

연산자 오버로드가 제공되는 한 A 및 B는 C ++에서 모든 유형이 될 수 있습니다. Java에서 A와 B가 프리미티브가 아닌 경우 프리미티브와 유사한 객체 (BigInteger 등)의 경우에도 코드가 매우 혼란 스러울 수 있습니다 ...

자연스러운 배열 / 컨테이너 접근 자 및 아래 첨자 :

// C++ container accessors, more natural
value        = myArray[25] ;         // subscript operator
value        = myVector[25] ;        // subscript operator
value        = myString[25] ;        // subscript operator
value        = myMap["25"] ;         // subscript operator
myArray[25]  = value ;               // subscript operator
myVector[25] = value ;               // subscript operator
myString[25] = value ;               // subscript operator
myMap["25"]  = value ;               // subscript operator

// Java container accessors, each one has its special notation
value        = myArray[25] ;         // subscript operator
value        = myVector.get(25) ;    // method get
value        = myString.charAt(25) ; // method charAt
value        = myMap.get("25") ;     // method get
myArray[25]  = value ;               // subscript operator
myVector.set(25, value) ;            // method set
myMap.put("25", value) ;             // method put

Java에서는 각 컨테이너가 동일한 작업을 수행하기 위해 (인덱스 또는 식별자를 통해 내용에 액세스) 다른 방법으로 수행하는 것이 혼란 스럽습니다.

C ++에서 연산자 오버로드 덕분에 각 컨테이너는 동일한 방식으로 콘텐츠에 액세스합니다.

자연스러운 고급 유형 조작

아래 예 Matrix는 Google에서 " Java Matrix object "및 " C ++ Matrix object " 에 대한 첫 번째 링크를 사용하여 찾은 객체를 사용합니다 .

// C++ YMatrix matrix implementation on CodeProject
// http://www.codeproject.com/KB/architecture/ymatrix.aspx
// A, B, C, D, E, F are Matrix objects;
E =  A * (B / 2) ;
E += (A - B) * (C + D) ;
F =  E ;                  // deep copy of the matrix

// Java JAMA matrix implementation (seriously...)
// http://math.nist.gov/javanumerics/jama/doc/
// A, B, C, D, E, F are Matrix objects;
E = A.times(B.times(0.5)) ;
E.plusEquals(A.minus(B).times(C.plus(D))) ;
F = E.copy() ;            // deep copy of the matrix

그리고 이것은 행렬에만 국한되지 않습니다. BigIntegerBigDecimal자바의 클래스는 C에서 자신의 등가물 ++로 반면, 같은 혼란 상세 고통 내장의 유형으로 취소합니다.

자연 반복자 :

// C++ Random Access iterators
++it ;                  // move to the next item
--it ;                  // move to the previous item
it += 5 ;               // move to the next 5th item (random access)
value = *it ;           // gets the value of the current item
*it = 3.1415 ;          // sets the value 3.1415 to the current item
(*it).foo() ;           // call method foo() of the current item

// Java ListIterator<E> "bi-directional" iterators
value = it.next() ;     // move to the next item & return the value
value = it.previous() ; // move to the previous item & return the value
it.set(3.1415) ;        // sets the value 3.1415 to the current item

자연 펑터 :

// C++ Functors
myFunctorObject("Hello World", 42) ;

// Java Functors ???
myFunctorObject.execute("Hello World", 42) ;

텍스트 연결 :

// C++ stream handling (with the << operator)
                    stringStream   << "Hello " << 25 << " World" ;
                    fileStream     << "Hello " << 25 << " World" ;
                    outputStream   << "Hello " << 25 << " World" ;
                    networkStream  << "Hello " << 25 << " World" ;
anythingThatOverloadsShiftOperator << "Hello " << 25 << " World" ;

// Java concatenation
myStringBuffer.append("Hello ").append(25).append(" World") ;

자, Java MyString = "Hello " + 25 + " World" ;에서도 사용할 수 있습니다 ... 그러나 잠시만 기다리십시오. 이것은 연산자 오버로드입니다. 그렇지 않습니까? 부정 행위 아닌가요 ???

:-디

일반 코드?

내장 / 프리미티브 (Java에 인터페이스가없는), 표준 객체 (올바른 인터페이스를 가질 수 없음) 및 사용자 정의 객체 모두에 동일한 일반 코드 수정 피연산자를 사용할 수 있습니다.

예를 들어, 임의 유형의 두 값의 평균값을 계산합니다.

// C++ primitive/advanced types
template<typename T>
T getAverage(const T & p_lhs, const T & p_rhs)
{
   return (p_lhs + p_rhs) / 2 ;
}

int     intValue     = getAverage(25, 42) ;
double  doubleValue  = getAverage(25.25, 42.42) ;
complex complexValue = getAverage(cA, cB) ; // cA, cB are complex
Matrix  matrixValue  = getAverage(mA, mB) ; // mA, mB are Matrix

// Java primitive/advanced types
// It won't really work in Java, even with generics. Sorry.

운영자 과부하 논의

이제 연산자 오버로딩을 사용하는 C ++ 코드와 Java의 동일한 코드를 공정하게 비교 했으므로 이제 "오퍼레이터 오버로드"를 개념으로 설명 할 수 있습니다.

컴퓨터 이전부터 운영자 과부하가 발생했습니다.

심지어 외부 컴퓨터 과학, 연산자 오버로딩이있다 : 예를 들어, 수학, 사업자 좋아 +, -, *오버로드, 등.

실제로,의 의미 + , -,* 등의 변화 피연산자의 종류 (수치 등, 벡터 양자 파동 함수, 행렬)에 따라.

우리 대부분은 과학 과정의 일부로서 피연산자의 유형에 따라 연산자에 대한 여러 가지 의미를 배웠습니다. 혼란 스러웠습니까?

연산자 오버로드는 피연산자에 따라 다릅니다.

이것은 연산자 오버로딩의 가장 중요한 부분입니다. 수학이나 물리학 에서처럼 연산은 피연산자의 유형에 따라 다릅니다.

따라서 피연산자의 유형을 알고 작업의 효과를 알게됩니다.

C와 Java조차도 (하드 코딩 된) 연산자 오버로드가 있습니다.

C에서 연산자의 실제 동작은 피연산자에 따라 변경됩니다. 예를 들어, 두 개의 정수를 추가하는 것은 두 개의 double을 추가하거나 하나의 정수와 double을 추가하는 것과 다릅니다. 전체 포인터 산술 도메인도 있습니다 (캐스팅하지 않고 포인터에 정수를 추가 할 수는 있지만 두 개의 포인터를 추가 할 수는 없습니다 ...).

Java에서는 포인터 산술이 없지만 +"연산자 오버로드가 악의적"이라는 신념에서 예외를 정당화 할만큼 조작자가 없는 문자열 연결은 여전히 우스운 것으로 판명되었습니다 .

C (역사적 이유로) 또는 Java ( 개인적 이유로 아래 참조) 코더 로서 자신만을 제공 할 수는 없습니다.

C ++에서 연산자 오버로딩은 선택 사항이 아닙니다 ...

C ++에서는 내장 유형에 대한 연산자 오버로드가 불가능하지만 (이것은 좋습니다) 사용자 정의 유형에는 사용자 정의 유형이있을 수 있습니다 연산자 오버로드 .

앞서 언급했듯이 C ++ 및 Java와 달리 사용자 유형은 내장 유형과 비교할 때 언어의 2 급 시민으로 간주되지 않습니다. 따라서 내장 유형에 연산자가 있으면 사용자 유형도 연산자를 가질 수 있어야합니다.

진실은 저를 인처럼 toString(), clone(), equals()방법은 자바위한 것입니다 ( 즉, 준 표준 등 ), C ++ 연산자 오버로딩이 언급 Java 메소드 전에 원래 C 사업자 등의 자연, 또는으로 될 것으로 ++ C의 너무 많은 부분입니다.

템플릿 프로그래밍과 결합 된 연산자 오버로딩은 잘 알려진 디자인 패턴이됩니다. 실제로 오버로드 된 연산자를 사용하지 않고 자신의 클래스에 대한 오버로드 연산자를 사용하지 않으면 STL에서 멀리 갈 수 없습니다.

...하지만 남용해서는 안됩니다

연산자 과부하는 연산자의 의미를 존중하기 위해 노력해야합니다. +연산자 에서 빼지 마십시오 ( " add함수 에서 빼지 마십시오 "또는 " clone메소드 에서 크랩 반환 ").

캐스트 과부하는 모호성을 유발할 수 있으므로 매우 위험 할 수 있습니다. 따라서 실제로 정의 된 사례를 위해 예약해야합니다. 에 관해서 &&그리고 ||당신이 정말로 당신이 무슨 일을하는지 알지 못한다면 당신은 기본 운영자 그 단락 회로 평가를 잃게됩니다로서, 지금까지 그들을 과부하가 걸리지 않도록 &&하고 ||즐길 수 있습니다.

그렇다면 ... Ok ... 그렇다면 왜 Java에서는 불가능합니까?

제임스 고슬링이 그렇게 말했기 때문에 :

C ++에서 너무 많은 사람들이 그것을 남용하는 것을 보았 기 때문에 연산자 오버로드를 상당히 개인적인 선택으로 제외 했습니다.

제임스 고슬링 출처 : http://www.gotw.ca/publications/c_family_interview.htm

위의 Gosling의 텍스트를 Stroustrup의 아래 텍스트와 비교하십시오.

많은 C ++ 디자인 결정은 사람들이 특정한 방식으로 일을하도록 강요하는 것에 대해 싫어하는 데 뿌리를두고있다. [...] 종종, 나는 개인적으로 싫어하는 기능을 불법화하려는 유혹을 받았다. 다른 사람에 대한 나의 견해를 강요 할 권리 .

Bjarne Stroustrup. 출처 : C ++의 디자인과 진화 (1.3 일반 배경)

연산자 과부하가 Java에 도움이됩니까?

일부 객체는 연산자 오버로드 (BigDecimal, 복소수, 행렬, 컨테이너, 반복자, 비교기, 파서 등과 같은 콘크리트 또는 숫자 유형)의 이점을 크게 누릴 수 있습니다.

C ++에서는 Stroustrup의 겸손으로 인해이 혜택을 누릴 수 있습니다. Java에서는 Gosling이 개인적으로 선택 했기 때문에 문제가 발생했습니다 .

Java에 추가 할 수 있습니까?

현재 Java에 운영자 과부하를 추가하지 않는 이유는 내부 정치, 기능에 대한 알레르기, 개발자에 대한 불신 (Java 팀을 괴롭히는 것처럼 보이는 파괴자), 이전 JVM과의 호환성, 정확한 사양 작성 시간 등

따라서이 기능을 기다리는 숨을 참지 마십시오 ...

그러나 그들은 C #으로 그것을합니다!

네...

이것이 두 언어의 유일한 차이점은 아니지만이 언어는 결코 나를 즐겁게하지 않습니다.

분명히 C # 사람들은 "모든 프리미티브는 a struct이고 structObject에서 파생됩니다"라는 첫 번째 시도에서 올바르게 얻었습니다.

그리고 그들은 다른 언어 로도 합니다 !!!

모든에도 불구하고 FUD 사용 정의 연산자 오버로딩에 대해, 다음과 같은 언어를 지원 : 스칼라 , 다트 , 파이썬 , F 번호 , C #을 , D , 알골 (68) , 스몰 토크 , 그루비 , 펄 6 , C ++, 루비 , 하스켈 , MATLAB , 에펠 , 루아 , Clojure , Fortran 90 , Swift , Ada , Delphi 2005 ...

너무나 많은 다른 (때때로 반대되는) 철학을 가진 많은 언어들이 있지만, 그들은 모두 그 시점에 동의합니다.

생각할 거리...


50
이것은 훌륭한 답변입니다. 나는 그것에 동의하지 않지만 여전히 훌륭한 대답입니다. 잘못된 과부하로 인해 발생할 수있는 문제가 우수한 과부하 값을 초과한다고 생각합니다.
Douglas Leeder

69
@ Douglas Leeder : 감사합니다! 연산자 오버로드는 OOP와 같습니다. 처음으로 배우면 기본 클래스와 상속을 어디에나 배치 할 때 (예 : 달콤한 아이러니, Java API) 오버로드를 작성합니다. 그러나 이것은 매우 빨리 지나가고 당신은 그것을 학대하지 않는 동안 가능성을 높이 평가합니다. C ++에 대한 10 년 이상의 경험은 내 코드와 다른 코더의 코드에서 볼 수있는 나쁜 과부하가 너무 적어서 한 손으로 계산할 수 있다고 생각합니다. 그리고 이것은 sprintf, strcat, memset 및 buffer overrun과 관련된 전체 버그 수보다 훨씬 적습니다.
paercebal

11
@ Douglas Leeder : 또 다른 SO 질문에서 그것에 대해 논의한 후 연산자 과부하의 "연인"과 "해시 자"의 차이는 코드 접근 방식의 차이로 인한 것일 수 있다고 생각합니다. "Haters"는 "기능" 중요한 것은 "함수는 하나의 기능 만 수행 할 수 있다는 것을 의미합니다. 따라서 운영자는 언어로 설계된대로 작동해야합니다. "연인"은 "객체가 행동해야한다"에 관한 것입니다. 즉, 기능 (및 연산자)이 매개 변수 유형에 따라 행동을 변경할 수 있다는 것을 더 쉽게 받아들입니다.
paercebal

103
에픽 답변. 내가 읽은 최고의 자격 중 하나.
Sebastian Mach

7
@MaartenBodewes : 위에서 쓴 모든 예제와 당신을 괴롭히는 모든 것은 "개발자로서 Gosling의 개인적인 선택 때문에 망가졌습니다 " ? 제발, 자신의 답변을 작성하여 "당신은 개발자가 바보, 천재 사람들이 당신에게 필요한 것을 결정하게" 각도를 . 이 토론은 목적이 없습니다.
paercebal

44

James Gosling은 Java 디자인을 다음과 같이 비유했습니다.

"한 아파트에서 다른 아파트로 이사 할 때 이사하는 것에 대한이 원칙이 있습니다. 흥미로운 실험은 아파트를 포장하고 모든 것을 상자에 넣은 다음 다음 아파트로 옮기고 필요할 때까지 포장을 풀지 않는 것입니다. 첫 식사를 다시하고 상자에서 무언가를 꺼내는 것입니다. 그리고 한 달 정도 지나면 인생에서 실제로 필요한 것들을 거의 파악하고 나머지는 물건-좋아하는 것과 잊어 버리는 것을 잊어 버리고 그냥 버려라 인생을 단순화시키는 방법이 놀랍고 모든 종류의 디자인 문제에서 그 원칙을 사용할 수 있습니다. '멋지거나 재미 있기 때문에.'

여기에서 인용문문맥을 읽을 수 있습니다

기본적으로 연산자 과부하는 일종의 포인트, 통화 또는 복소수를 모델링하는 클래스에 적합합니다. 그러나 그 후에는 예제가 빨리 부족하기 시작합니다.

또 다른 요인은 개발자가 '&&', '||', 캐스트 연산자 및 물론 'new'와 같은 연산자를 오버로드하는 개발자가 C ++의 기능을 남용하는 것입니다. 이를 통과 가치 및 예외와 결합하여 발생하는 복잡성에 대해서는 예외적 인 C ++ 책 .


6
"값에 따른 예외 및 예외와 결합 된 연산자 오버로드의 복잡성"에 대한 코드 예제를 제공 할 수 있습니까? 몇 년 동안 언어를 사용하고 C ++에 대한 모든 효과적인 / 예외 책을 소유하고 읽었지만 그럼에도 불구하고 그 의미가 무엇인지 이해하지 못합니다.
paercebal

60
제임스 고슬링에게 효과가있는 것은 모든 사람에게 효과가 없을 것입니다. 그는 자신의 "흥미로운"포장 실험을 외삽하여 "내가 필요하지 않은 모든 것을 버리므로 아무도 그 물건을 사용할 수 없다"는 뜻으로 엄청나게 근시안적입니다. 그는 내가 필요로하거나 무엇을 사용하는지 명확하게 알지 못한다.
BT

49
@BT :이 문제에 대한 Stroustrup의 관점과 비교할 때 가장 깨달은 것은 Gosling의 관점 Many C++ design decisions have their roots in my dislike for forcing people to do things in some particular way [...] Often, I was tempted to outlaw a feature I personally disliked, I refrained from doing so because I did not think I had the right to force my views on others. (B. Stroustrup)입니다.
paercebal

29
@Software Monkey : "C ++, 다른 Java와 비교하여 널리 비난 받음"이 광고는 과대 광고입니다. C ++은 단독으로 성장한 반면 Java (및 .NET)는 마케팅 불도저에서 이익을 얻었습니다. "광범위한 언어"의 경우 Java가 서버 응용 프로그램으로 제한되는 반면 "광범위한"(아마도 Java 개발자 및 관리자가 코드 생성 비용을 낮추고 자 함) C ++은 매우 높은 수준에서 나온다는 것이 이상하게 보이지 않습니다. 고성능 게임에서 고성능 서버까지? [...]
paercebal

16
@Hassan : 각 언어에는 해킹이 있으며 Java의 제네릭은 그 중 하나입니다. 이제, I'd like them to go have a look at some C++ code out there that is hideously put together with weird hacks and "exceptional" features of the language나쁜 프로그래머는 언어에 관계없이 나쁜 코드를 작성합니다. Java에서 함수 매개 변수에 대한 "통과 기준"을 모방하여 아이디어를 얻으십시오. 나는 코드를 보았고 너무 힘들어 웃었다. 이것은 Gosling이 사용하지 않은 종류이므로 Java에서 끔찍한 해킹이 필요했지만 C #과 C ++ 모두 기본적으로 비용이 들지 않습니다.
paercebal

22

Boost.Units를 확인하십시오. 링크 텍스트

작업자 과부하를 통해 오버 헤드없는 차원 분석을 제공합니다. 이것이 얼마나 더 명확합니까?

quantity<force>     F = 2.0*newton;
quantity<length>    dx = 2.0*meter;
quantity<energy>    E = F * dx;
std::cout << "Energy = " << E << endl;

실제로 "에너지 = 4J"를 출력합니다.


1
"정확히 유지 보수가 복잡하고 지구상 어디에서 코드가 난독 화 되는가?"
Mooing Duck

13

자바 디자이너들은 연산자 오버로딩이 가치가있는 것보다 더 많은 문제라고 판단했다. 그렇게 간단합니다.

모든 객체 변수가 실제로 참조 인 언어에서 연산자 오버로딩은 적어도 C ++ 프로그래머에게는 비논리적 인 추가 위험을 초래합니다. 상황을 C #의 == 연산자 오버로드 및 Object.EqualsObject.ReferenceEquals(또는 호출 된 모든 것과) 비교하십시오.


8

Groovy 는 연산자 오버로딩을 가지고 있으며 JVM에서 실행됩니다. 성능 저하를 신경 쓰지 않으면 (매일 더 작아집니다). 메소드 이름에 따라 자동으로 수행됩니다. 예를 들어, '+'는 'plus (argument)'메소드를 호출합니다.


4
연산자 오버로드가있는 모든 구문이 많은 언어가 해당 기술을 사용하기를 바랍니다. 왜 그들이 특수한 버전의 메소드 명명 및 조회를 개발해야하는지 이해하지 못했습니다. Stroustrup은 D & EC ++의 대안을 언급하지 않습니다. C # 팀은 Linq 구문을 사용하여 올바른 접근 방식을 취했습니다 ( where ...가 됨 .Where(i => ... ). 산술 연산자로만 동일한 작업을 수행하면 훨씬 더 간단하고 강력 해집니다. Java는 깨끗한 슬레이트의 이점을 가지고 있으며, 올바른 방법으로 얻을 수 있습니다.
다니엘 Earwicker

@DanielEarwicker, 나는 종종 사람들이 복잡한 의견 차이가있을 때 사람들이 자연적으로 "종교적"인 것으로 양쪽의 동기를 표시한다고 언급했습니다.

@noah, 메소드 이름에 시각적으로 구별되는 특별한 태그가 있다면, 이와 같은 연산자 오버로드의 제한된 하위 집합으로 살 수 있습니다. "+"OL의 구현을 위해 __plus () 메소드를 정의하고 캐스트 및 배열 첨자 같은 것들을 너무 많이 오버로드하는 것과 같은 것. 내가 살고 싶지 않은 것은 C ++과 C #이 그것을 구현하기에 적합한 방식입니다.

2
답이 아닙니다. VM에서 많은 언어가 실행되고 있습니다. 언어를 바꾸는 연산자 오버로드 자체가 좋은 이유는 아닙니다.
Maarten Bodewes

6

필자는 이것이 의도적으로 의도를 전달하는 이름을 가진 함수를 개발자가 만들도록 의식적인 디자인 선택 일 수 있다고 생각합니다. C ++에서 개발자는 종종 주어진 연산자의 일반적으로 받아 들여지는 특성과 관련이없는 기능을 가진 연산자를 오버로드하여 연산자의 정의를 보지 않고 코드 조각이 무엇인지 판단하는 것이 거의 불가능합니다.


14
In C++ developers would overload operators with functionality that would often have no relation to the commonly accepted nature of the given operator: 이것은 무의미한 주장입니다. 나는 12 년 이후로 전문적인 C ++ 개발자 이며이 문제는 거의 발생하지 않습니다. 사실, C ++에서 보았던 대부분의 버그와 디자인 오류는 C 스타일 코드 ( void *, 캐스트 등)에
있었습니다

6
-1. 할당하는 모든 변수는 산술 연산자 기호와 마찬가지로 기호입니다. 해당 변수의 이름을 지정하기 위해 문구를 사용하든, 한 단어 또는 한 글자를 사용 하느냐는 귀하 (또는 팀의 결정)입니다. 의미있는 것과 그렇지 않은 것을 누가 말해야합니까? 답은 프로그래머입니다. 순수한 수학에서 행렬 간 곱셈은 기본 산술에서 두 숫자 간 곱셈과는 다른 의미입니다. 그러나 우리는 두 유형의 곱셈에 동일한 기호를 사용합니다.
엔지니어

2
@paercebal : 불행히도 주장이 맞습니다. 실제 동작을보기 위해 IOstream보다 더 멀리 보지 않아도됩니다. 고맙게도 대부분의 개발자는 기존 운영자를위한 새로운 의미 체계를 개발하는 데 더 신중해야합니다.
벤 Voigt

5
@BenVoigt : [...] 그리고 add함수가 실제로 잘못 사용 될 수 있다는 사실에 대해서도 언급하고 있지 않습니다 (곱셈을 수행하거나 뮤텍스를 얻는 것과 같이). user14128이 언급 한 남용은 연산자에 국한되지 않지만 연산자 오버로드에 대한 일종의 병리학 적 두려움이 있습니다 .C vs. C ++의 초기 시대에서 왔으며 Java로 수정되지 않은 두려움입니다.하지만 고맙게도 C #으로 들어 가지 않았습니다 ... 시맨틱을 존중합니다. 명확한 기능 / 연산자를 작성하는 것은 개발자의 일입니다. 언어가 아닙니다.
paercebal

3
@ jbo5112 : 예 : cout << f() || g(); 괄호는 명확하지 않고 정확합니다. 그리고 비트 시프트 연산자는 남용되지 않았으므로 필요하지 않았습니다. 왜 cout << (5&3) << endl;보다 낫 cout.fmt(5&3)(endl);습니까? functor 멤버 변수에 함수 호출 연산자를 사용하면 글리프가 멋지게 보이기 때문에 비트 연산자를 용도 변경하는 것보다 스트림에 대해 무한히 더 나은 디자인이됩니다. 그러나 이것은 스트림에 잘못된 유일한 것은 아닙니다.
벤 Voigt

5

글쎄, 운전자 과부하로 실제로 발을 쏠 수 있습니다. 그것은 사람들이 그들과 어리석은 실수를 저지르는 포인터와 같으므로 가위를 치우기로 결정했습니다.

적어도 나는 그것이 이유라고 생각합니다. 어쨌든 난 네 편이야 :)


예를
들어이

2
그것은 매우 나쁜 생각입니다. 당신은 발로 자신을 쏠 수 있습니다, 우리는 오히려 손을 잘라서, 당신은 할 수 없습니다. 그리고 물론 우리는 당신이 자신을 쏠 바보라고 가정합니다.
ntj

5

어떤 사람들은 자바에서 연산자 오버로드가 난독 화로 이어질 것이라고 말합니다. 그 사람들은 BigDecimal을 사용하여 재무 가치를 백분율로 높이는 것과 같은 기본적인 수학을하는 Java 코드를 보지 않으셨습니까? .... 그러한 운동의 자세한 표현은 난독 화에 대한 자체의 증명이됩니다. 아이러니하게도, 연산자 오버로딩을 Java에 추가하면 고유 한 Currency 클래스를 만들어 수학적 코드를 우아하고 단순하게 만들 수 있습니다.


4

연산자 오버로드로 인해 연산자가 운영 논리와 일치하지 않는 유형의 논리적 오류가 발생한다고 말하는 것은 아무 것도 말하지 않는 것과 같습니다. 함수 이름이 연산 로직에 적합하지 않은 경우 동일한 유형의 오류가 발생합니다. 따라서 해결책은 무엇입니까? 이것은 "작동 논리에 적합하지 않음", 모든 매개 변수 이름, 모든 클래스, 함수 또는 논리적으로 부적절 할 수있는 것 같은 코믹한 답변입니다. 이 옵션은 프로그래밍 가능한 언어로 사용할 수 있어야하며 안전하지 않다고 생각하는 사람들은이 옵션을 사용해야한다고 생각합니다. C #을 보자. 그들은 포인터를 떨어 뜨 렸지만 당신은 자신의 위험에 따라 원하는대로 '안전하지 않은 코드'문구가 있습니다.


4

기술적으로, 모든 프로그래밍 언어에는 정수 및 실수와 같은 다른 유형의 숫자를 처리 할 수있는 연산자 오버로드가 있습니다. 설명 : 오버로딩이라는 용어는 하나의 함수에 대해 단순히 여러 구현이 있음을 의미합니다. 대부분의 프로그래밍 언어에서 연산자 +, 정수, 실수, 실수에 대해 서로 다른 구현이 제공됩니다. 이것을 연산자 오버로딩이라고합니다.

이제 많은 사람들이 Java에 연산자에 대한 연산자 과부하가 있고 문자열을 함께 추가하기 때문에 이상하다고 생각합니다. 수학적 관점에서 보면 이것이 이상하게 보일 수는 있지만 프로그래밍 언어 개발자의 입장에서 볼 때 내장 연산자 오버로드를 추가해도 아무런 문제가 없습니다. 연산자 + 다른 클래스 (예 : 문자열) 그러나 대부분의 사람들은 + for String에 내장 과부하를 추가하면 일반적으로 개발자에게도이 기능을 제공하는 것이 좋습니다.

연산자 오버로드로 인해 코드가 난독 화된다는 오류에 완전히 동의하지 않습니다. 이는 개발자가 결정할 수 있기 때문입니다. 이것은 생각하기에 순진하고 아주 정직하기 때문에 나이가 들었습니다.

Java 8에서 연산자 오버로드를 추가하기위한 +1


+문자열과 같은 것을 연결 하는 Java의 사용 은 IMHO가 매우 무시 무시합니다 /.C 및 FORTRAN의 전체 및 분수 분할에 대한 과부하입니다 . 많은 버전의 Pascal에서 모든 숫자 유형에 산술 연산자를 사용하면 피연산자를로 변환하는 것과 같은 Real결과를 얻을 수 있지만 정수가 아닐 수있는 결과 는 정수를 통해 할당되기 전에 공급 Trunc되거나 전달되어야합니다 Round.
supercat

2

Java를 구현 언어로 가정하면 a, b 및 c는 모두 초기 값이 null 인 Complex 유형에 대한 참조입니다. 또한 언급 된 BigInteger 및 유사한 불변의 BigDecimal 과 같이 Complex가 변경 불가능하다고 가정 하면 b와 c를 추가하여 반환 된 Complex에 대한 참조를 할당 하고이 참조를 a와 비교하지 않기 때문에 다음을 의미한다고 생각합니다.

아닙니다 :

Complex a, b, c; a = b + c;

다음보다 훨씬 간단합니다.

Complex a, b, c; a = b.add(c);

2
내가? ;) 같음은 대입 또는 비교를 의미 할 수 있지만 =는 항상 대입이고 ==는 항상 비교입니다. 이름으로 인해 큰 오류가 발생할 수 있습니다.

1

때로는 연산자 오버로드, 친구 클래스 및 다중 상속을 갖는 것이 좋을 수도 있습니다.

그러나 나는 여전히 좋은 결정이라고 생각합니다. Java가 연산자 오버로딩을 가졌다면 소스 코드를 보지 않고도 연산자 의미를 확신 할 수 없었습니다. 현재는 필요하지 않습니다. 그리고 연산자 오버로드 대신 메소드를 사용하는 예제도 읽을 수 있다고 생각합니다. 더 명확하게하고 싶다면 항상 털이 많은 문장 위에 주석을 추가 할 수 있습니다.

// a = b + c
Complex a, b, c; a = b.add(c);

12
물론 다른 곳에서 언급했듯이 add 함수의 의미를 확신 할 수 없습니다.
Eclipse

사실, 나는 여전히 내 운영자가 하드 코딩되어 있다는 것을 알고 편안하게 생각합니다. 물론 기능을 가지고 있고 현명하게 사용하는 것은 우리에게만 도움이 될 것입니다. 문제는 누군가가 그것을 현명하게 사용했는지 알기가 어렵다는 것입니다. 그리고 당신은 현명하게 정의에 동의합니다. :-)

1
코드를 명확하게하기 위해 추가 된 주석은 연산자 오버로드를 지원하는 언어에서 코드가 어떻게 보이는지입니다. 또한 주석이 연산자로 작성되었다는 사실은 연산자 오버로드에 대한 반대 의견입니다.
Aluan Haddad

0

이것이 허용하지 않는 좋은 이유가 아니라 실용적인 이유입니다.

사람들은 항상 책임감있게 그것을 사용하지는 않습니다. Python 라이브러리 scapy에서이 예제를보십시오.

>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>

설명은 다음과 같습니다.

/ 연산자는 두 레이어 사이의 작성 연산자로 사용되었습니다. 그렇게 할 때, 하위 계층은 상위 계층에 따라 하나 이상의 기본 필드가 오버로드 될 수 있습니다. (여전히 원하는 값을 줄 수 있습니다). 문자열은 원시 레이어로 사용할 수 있습니다.


0

Java 연산자 오버로딩의 기본 지원에 대한 대안

Java에는 연산자 오버로드가 없으므로 다음과 같은 대안을 살펴보십시오.

  1. 다른 언어를 사용하십시오. GroovyScala 는 모두 연산자 오버로딩을 가지며 Java를 기반으로합니다.
  2. Java에서 연산자 오버로드를 가능하게하는 플러그인 java-oo를 사용하십시오 . 플랫폼 독립적이지 않습니다. 또한 많은 문제가 있으며 최신 릴리스의 Java (예 : Java 10)와 호환되지 않습니다. ( 원래 StackOverflow 소스 )
  3. JNI , Java Native Interface 또는 대안을 사용하십시오 . 이를 통해 Java에서 사용할 C 또는 C ++ (아마도 다른가?) 메소드를 작성할 수 있습니다. 물론 이것은 플랫폼과 무관합니다.

누구든지 다른 사람을 알고 있다면 의견을 말하십시오.이 목록에 추가하겠습니다.


0

Java 언어는 연산자 오버로드를 직접 지원하지 않지만 Java 프로젝트에서 Manifold 컴파일러 플러그인 을 사용하여 활성화 할 수 있습니다. Java 8-13 (현재 Java 버전)을 지원하며 IntelliJ IDEA에서 완전히 지원됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.