2009-06-27 4 views
2

저는 수학 객체에 대한 추상화 클래스를 작성하고 모든 연산자를 정의했습니다. 그것을 사용하는 동안, 나는 가로 질러 온 :적절한 빼기 연산자 정의

Fixed f1 = 5.0f - f3; 

나는 두 뺄셈 연산자 정의 :

inline const Fixed operator -() const; 
inline const Fixed operator - (float f) const; 

나는 여기에서 잘못된 것은 얻을 - 또한이 스왑 (1 + 2 == 2 + 1)입니다 뺄셈은 아닙니다 (곱셈과 나눗셈에 대해서도 동일합니다). 나는 즉시 외부에서이 같은 내 클래스 함수 를 썼다 :

static inline const Fixed operator - (float f, const Fixed &fp); 

을하지만 그때 나는 키워드 friend를 사용하여 어떤 결과 클래스의 음부를 터치했을 것이라고 할 때문에이 수행 할 수 없습니다 실현 나는 싫어하고 '정적 인'불필요한 기능으로 네임 스페이스를 오염시킨다. 클래스 정의 수율 내부 GCC-4.3이 오차 함수을 이동

:

error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument 
:

error: ‘static const Fixed Fixed::operator-(float, const Fixed&)’ must be either a non-static member function or a non-member function 

은 GCC가 제안 하하고 그것을 비 정적 기능을 다음과 같은 오류가 발생

왜 클래스 정의 내에 동일한 연산자를 정의 할 수 없습니까? 할 방법이 없다면 friend 키워드를 사용하지 않는 것이 있습니까?

똑같은 문제로 고통받는 동일한 질문이 나누기에 해당됩니다.

답변

3

확인을 할 수있는 친구 기능을 안심해야하는 경우 :

당신은 캠프은 "왼쪽 인수에 변환을 필요로하는 작업"에

http://www.gotw.ca/gotw/084.htm

Which operations need access to internal data we would otherwise have to grant via friendship? These should normally be members. (There are some rare exceptions such as operations needing conversions on their left-hand arguments and some like operator<<() whose signatures don't allow the *this reference to be their first parameters; even these can normally be nonfriends implemented in terms of (possibly virtual) members, but sometimes doing that is merely an exercise in contortionism and they're best and naturally expressed as friends.)

. 당신이 친구를 원하고, 가정하지 않으면 Fixed for 아닌 명시 적 float 생성자가, 당신이 그것을 구현할 수 :

static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) { 
    return lhs.minus(rhs); 
} 

다음 공용 멤버 함수로 minus을 구현, 대부분의 사용자는하지 않습니다 그들이 연산자를 선호하기 때문에 귀찮아. 당신이 명시 적 float 생성자가있는 경우

static inline Fixed operator-(float lhs, const Fixed &rhs) { 
    return (-rhs) + lhs; 
    // return (-rhs) -(-lhs); if no operator+... 
} 

하거나 Fixed(lhs) - rhs : 당신이 변환 연산자가없는 경우, 당신이 갈 수 있도록 operator-(float)이있는 경우 나 가정

는 당신이 operator+(float) 있습니다.그것들은 당신의 친구 구현만큼 효율적일 수도 아닐 수도 있습니다. 운영자는 정적 멤버 함수 일 우정의 효과를 얻을 수 있도록

불행하게도 언어는 그 키워드 중 하나를 혐오하는 일이 사람들을 수용하기 위해 거꾸로 구부릴하지 않을 그런 식으로 ;-p

1
  1. 당신은 (float를 받아들이는 생성자 등) float과 형식 사이의 암시 적 변환을 추가 할 수 있습니다 ...하지만 나는 friend 사용하여 생각 "그건 친구가 무엇을 ...입니다" 더 나은.
+1

2는 실제로 "고정 (0.5f) - f3" implict 변환은 멤버 함수로 구현 된 연산자의 lhs에 결코 일어나지 않습니다. 실제로 "this"는 호출자가 제공하는 것이지 일시적인 것이 아닙니다. –

+0

lhs를 해당 연산자가있는 모든 유형으로 변환 할 수 있다면 이름 결정의 완전히 새로운 차원을 갖게되어 표준위원회의 취향에 너무 많은 모호함을 초래할 수 있습니다. –

0

이 같은 무언가를 정의 할 때

inline const Fixed operator - (float f) const; 

당신은 내가이 연산자가 (당신이 클래스 안에있는), 특정 유형에서 작동 예를 들어 여기에 부유 할 것을 말하고있다.

친구 이진 연산자는 두 가지 유형 간의 연산을 의미합니다.

class Fixed 
{ 
    inline friend const Fixed operator-(const Fixed& first, const float& second); 
}; 

inline const Fixed operator-(const Fixed& first, const float& second) 
{ 
    // Your definition here. 
} 

친구 연산자를 사용하면 연산자의 어느쪽에도 수업을 가질 수 있습니다.

0

일반적으로 산술 연산을위한 자유 함수 연산자는 멤버 함수를 구현하는 것보다 낫습니다. 주된 이유는 지금 당면하고있는 문제입니다. 컴파일러는 왼쪽과 오른쪽을 다르게 처리합니다. 엄격한 OO 추종자는 클래스 내의 중괄호 중 하나만 인터페이스를 고려하지만, C++에서는 전문가가 아닌 argued을 사용합니다.

무료 기능 운영자가 비공개 회원에게 액세스해야하는 경우 운영자를 친구로 지정하십시오. 결국 동일한 헤더 파일 (위의 Sutter의 이론적 근거)에 제공된 경우 클래스의 일부입니다.

코드를 실제로 사용하지 않고 코드를 덜 관성적으로 (그리고 덜 유지 보수 가능하도록) 만들려는 경우 실제 작업을 수행하고 운영자로부터 해당 메소드로 디스패치하는 공용 메소드를 제공 할 수 있습니다. 위의 코드에서

class Fixed { 
private: 
    Fixed(); 
    Fixed(double d); // implicit conversion to Fixed from double 

    Fixed substract(Fixed const & rhs) const; 
// ... 
}; 

Fixed operator-(Fixed const & lhs, Fixed const & rhs) 
{ 
    return lhs.substract(rhs); 
} 

, 당신은 Fixed - Fixed, Fixed - double, double - Fixed을 빼지 수 있습니다. 컴파일러는 자유 함수를 찾아 double 생성자를 통해 예제에서 double을 Fixed 개체로 암시 적으로 변환합니다.

이것은 산술 연산자에 대해 일률적이지만 다형성 덤프 연산자를 증명하는 관용적 방법에 가깝습니다. 그래서 가장 자연스러운 해결책이 아니기는하지만 가장 놀랄만 한 코드가 아닐지라도

// idiomatic polymorphic dump operator 
class Base { 
public: 
    virtual std::ostream& dump(std::ostream &) const; 
}; 
std::ostream& operator<<(std::ostream& o, Base const & d) 
{ 
    return d.dump(o); 
}