2013-09-05 1 views
0

나는 시험 과제 중 하나에 약간의 문제가 있습니다. 이 텍스트입니다 :C++로 연산자 + 오버플로

클래스 MyFloat에는 private 변수 float num이 있습니다. 다음 코드 행을 사용할 수있는 메소드를 작성해야합니다. MyFloat x = 3.5; MyFloat의 Y = X + 3.2 플로트 Z = 3.4 +

하고이 코드 물품 Y :

float z = 3.4 + y; 

그것은 말한다

#include <iostream> 
#include <Windows.h> 
using namespace std; 

class MyFloat 
{ 
    float num; 
public: 
    MyFloat(float n) 
    { 
     num = n; 

    } 
    MyFloat operator+(MyFloat x) 
    { 
     float result; 
     result = x.num + this->num; 
     return result; 
    } 
}; 

int main() 
{ 
    MyFloat x = 3.75; 
    MyFloat y = x + 3.2; 
    float z = 3.4 + y; 
    system("PAUSE"); 
} 

난이 라인 오류를 :

오류 C2677 : 바이너리 '+': 글로벌 op 없음 'MyFloat'유형을 사용하는 에터레이터 (또는 허용되는 변환이 없음)

어떻게해야합니까? 이 문제를 해결하는 방법 ???

+3

당신은'가 +'비 멤버 함수를 확인해야합니다. –

+0

비회원 연산자 오버로드를 만들 수 있습니다. – IdeaHat

+0

C++에서 연산자 오버로드를 수행 한 지 오래되었지만 'MyFloat operator + (float x) {return num + x; }'? 그는 'MyFloat' 인스턴스에 네이티브'float'을 추가하고 있습니다. – crush

답변

5

이 해결책이 될 수 있습니다 : 나는하지만 MyFloat operator+(MyFloat, MyFloat) 비회원 친구 기능을 만드는 방법에 대한 여전히 라인을하지 않습니다하지만 또한, 처음

class MyFloat 
{ 
    float num; 
public: 
    MyFloat(float n) 
    { 
     num = n; 
    } 

    operator float() const { 
     return num; 
    } 
}; 

int main() 
{ 
    MyFloat x = 3.75; 
    MyFloat y = x + 3.2f; 
    float z = 3.4f + y; 
} 

float z = 3.4 + y;

에 엮다. 그 이유는 3.4 + yMyFloat 유형이므로 MyFloat에서 float으로 변환 연산자를 제공하지 않는 한 float z에 할당 할 수 없기 때문입니다. 그렇다면은으로 전화를 걸 수 있습니다. 또는 을 호출 할 수 있고 으로 y을 변환하고 float에는 기본 제공 연산자 +을 사용할 수 있기 때문에 3.4f + y은 모호합니다 (최소한 VS 2010의 경우).

+0

이것은 작동했습니다 ... 대단히 감사합니다! –

+0

이것이 작동합니다 (이것이 내가 답변을 upvoted 한 이유입니다).하지만 이것을 원하지 않는 경우가 있음을 알아 두는 것이 중요하다고 생각합니다. 예를 들어,'MyFloat'가'float' (http://crd-legacy.lbl.gov/~dhbailey/mpdist/)보다 큰 범위를 가지면,'MyFloat' 인스턴스를'float'로 변환하면 그 이점을 잃는다. –

+0

변환을 사용하는 것이 좋습니다. 때로는 사용할 때주의하십시오. – texasbruce

6

operator+을 2 개의 인수 MyFloat operator+(MyFloat x, MyFloat y)과 함께 비회원 친구 기능으로 구현하십시오.

왜 현재 버전에서 작동하지 않습니까? 멤버 연산자 함수는 연산자의 왼쪽에있는 객체에서 호출되기 때문에. 왼쪽에있는 경우에는 정수가 아니므로 객체가 아니기 때문에 MyFloat operator+(MyFloat x) 멤버 함수가 없습니다.

연산자의 비 멤버 변형은 대칭이므로 왼쪽면이 개체가 아니어도됩니다. 당신이 당신의 예에서 보는 바와 같이 우리가 수학


편집 생각하는 데 사용됩니다로 operator+ 대칭이 아니기 때문에 대칭성이 중요하다 그러나 의견 카시오 네리에 의해 언급 한 바와 같이이 아직 충분하지 않습니다. 왜? 설명에 대한 그의 대답을 보라. 간단히 말해서 : 모호성 문제가있다. 이 같은 수동 캐스팅을한다면 그의 솔루션이나이 솔루션을 사용할 수 있습니다 : float z = 3.4f + static_cast<float>(y); 이것은 꽤 못생긴 것입니다. MyFloat::operator float 변환을 제공하면 다른 캐스트 (float z = MyFloat(3.4f) + y)를 사용할 수 있습니다.

같은 모호성 문제를 해결하는 또 다른 방법 : C++ 11에서 당신이 예를 3.4_f을 위해, 내장 된 수레를 위해 f 접두사와 유사한 (문자 그대로 자신의 접미사를 사용할 수를 (밑줄 리터럴이 접미사는 사용자 -을 의미 . 당신이 MyFloat에서 뒤로 float과에 캐스팅 연산자를 구현하는 것이 주어진 정의) 샘플 구현 (:

MyFloat operator "" _f(long double val) { 
    return MyFloat(static_cast<float>(val)); } 

int main() { 
    MyFloat x = 3.75; 
    MyFloat y = x + 3.2; 
    float z = 3.4_f + y; 
} 
+0

당신의 대답은 위의 나의 코멘트를 깨끗하게한다. 감사. – crush

+0

의도는 좋지만'float z = 3 '행을 만들지 않습니다.4 + y;'컴파일합니다. 왜 내 게시물에보십시오. –

+0

나의 요점은'MyFloat 연산자 + (MyFloat, MyFloat)'가'MyFloat'를 반환한다는 사실이었습니다. 따라서 '3.4 + y' 표현식은'MyFloat' 유형입니다. 그러므로,'MyFloat'에서'float'으로 변환 연산자가 없다면,'float' ('float z = 3.4 + y')에 할당 될 수 없습니다. '3.4'가'double' 리터럴이고'float'에 할당 될 때 컴파일러는 (다소 짜증나는) 경고를냅니다. 그러나 이것은 여전히 ​​합법적 인 코드입니다. –

3

MyFloat +가 작업을 떠 있고, 당신도 + MyFloat 작동 플로트를 정의 할 필요가있다. 그들은 s가 아니다. 너.

는 공개 기능이 추가 :

friend float operator+ (const float& lhs, const MyFloat& rhs); 

그리고이 클래스 외부 :

float operator+ (const float& lhs, const MyFloat& rhs) { 
    return lhs + rhs.num; 
} 

참고 : CassioNeri에 의해 코멘트에 따라 편집을.

+0

거의! 유일한 문제는 rvalues에 바인딩 할 수없는 참조로 인수를 취하는 것입니다. 값 또는 참조 -to-const 중 하나를 사용하십시오. –

+0

@CassioNeri 편집 됨 .. – texasbruce

+0

그런 다음 +1하십시오. –

0

"캐스팅 - 플로트"방식을 정의 할 때 대답을 진행할 수 있지만 추가 기능을 구현하기 위해 공용 API를 사용하기 시작하는 것이 더 바람직하다고 생각합니다.

일반적으로 간단한 "캐스팅"은 트릭을 수행하지 않습니다 (예 : MyFloatMyMatrix 일 경우 어떻게됩니까?).

아래의 접근법은 분명히 더 장황하지만, "자신의 음식을 먹어야 함"을 강조합니다. 즉, 모호한 묵시적 캐스트가 아니라 자신의 공용 인터페이스를 기반으로하는 추가 동작을 구현해야한다는 것을 강조합니다. 또는 friend 함수. 자체 API를 사용하는 경우 : 제한 사항을 이해하고 수정할 경우 기본 클래스의 재 컴파일을 잠재적으로 저장할 수 있습니다.

또한 클래스에 대한 액세스를 계산하거나 기본 값에 대한 액세스를 제어하려는 경우 : 코드를 operator float()float value()에 복제해야하는 캐스팅 연산자를 사용한다고 가정합니다.

여기 내 겸손한 제안은 길지만 내 취향에 따라 OO 디자인 원칙을 잘 반영합니다. (g++ example.cpp -Wall -Wextra 컴파일)

#include<iostream> 

class MyFloat { 

public: 
    MyFloat(float value): 
     m_value(value) { } 

    float value() const { 
    return m_value; 
    } 

private: 
    float m_value; 

}; 

// Eat your own food: implement functions using your public interface 
// until proven need to do otherwise. This will help you assess the 
// usability of your API. 
float operator+(const MyFloat& lhs, const MyFloat& rhs) { return lhs.value() + rhs.value(); } 
float operator+(const MyFloat& lhs, float rhs) { return lhs.value() + rhs; } 
float operator+(float lhs, const MyFloat& rhs) { return lhs + rhs.value(); } 

// See, now I can define another operator without need to recompile my 
// class (this could have been placed in another file) 
std::ostream& operator<<(std::ostream& os, const MyFloat& mf) { 
    os<<"MyFloat("<<mf.value()<<")"; 
    return os; 
} 

int main() { 

    MyFloat x = 3.5;  // would not work if I had declared the constructor as "explicit" 
    MyFloat y = x + 3.2; 
    MyFloat z = 3.4 + y; 

    std::cout<<x<<", "<<y<<", "<<z<<std::endl; 
} 

출력 :

MyFloat(3.5), MyFloat(6.7), MyFloat(10.1)