2011-10-08 8 views
1

찾을 코드가 모두 접두사 연산자에 오버로드 될 때 참조 변수를 반환 할 때 혼란 스럽습니다. 나는 parashift.com FAQ (http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.14)를 훑어 보았지만 명확하지 않다고 밝혀졌지만 명확하지 않습니다. 당신이 그것을 읽을 때. 나는 그들의 예를 테스트 할 무분별하고 무의미한 작은 프로그램에 적용했다.C++ 접두사 오버로드에서 참조 변수를 반환합니다.

#include<iostream> 
using namespace std; 

class Number { 
    public: 
     Number operator++(); // prefix ++ 
     Number operator++ (int); // postfix ++ 
     int value() { return value_; } 
     void setValue(int value) { value_ = value; } 
    private: 
     int value_; 
}; 

Number Number::operator++() { 
    ++value_; 
    return *this; 
} 

Number Number::operator++ (int unused) { 
    Number temp; 
    temp.setValue(value_); 
    ++value_; 
    return temp; 
} 

int main() 
{ 
    Number someNum; 
    someNum.setValue(20); 
    cout << "someNum : " << someNum.value() << "\n"; 
    someNum++; 
    ++someNum; 
    cout << "someNum : " << someNum.value() << "\n"; 
    return 0; 
} 

나는 단순히 참조 변수의 더 나은 이해를 필요로 가정

#include<iostream> 
using namespace std; 

class Number { 
    public: 
     Number& operator++(); // prefix ++ 
     Number operator++ (int); // postfix ++ 
     int value() { return value_; } 
     void setValue(int value) { value_ = value; } 
    private: 
     int value_; 
}; 

Number& Number::operator++() { 
    ++value_; 
    return *this; 
} 

Number Number::operator++ (int unused) { 
    Number temp; 
    temp.setValue(value_); 
    ++value_; 
    return temp; 
} 

int main() 
{ 
    Number someNum; 
    someNum.setValue(20); 
    cout << "someNum : " << someNum.value() << "\n"; 
    someNum++; 
    ++someNum; 
    cout << "someNum : " << someNum.value() << "\n"; 
    return 0; 
} 

문제는 내가 너무 좋아뿐만 아니라 Number 객체로 선언하는 경우 작동입니다. 누구나 접두어 연산자가 왜 참조 변수를 반환하도록 코드화되어야하는지 간단하게 설명 할 수 있습니까?

답변

2

먼저 효율성 문제가 있습니다. 아무 이유없이 클래스를 반환하기 위해 클래스의 새 인스턴스를 만듭니다.

둘째, 의미 론적 문제가 있습니다. 코드는 빈 생성자 또는 복사 생성자를 호출하여 임시를 만든 다음 임시를 소멸시킵니다. 그것이 부적절한 의미 론적 의미를 지닌다면, 코드는 실제로 작동하지 않는다.

셋째, 코드가 잘못된 것을 반환합니다. 고려 : ++foo.do_something();. 코드를 사용하여 임시 객체에서 'do_something'을 호출합니다. 사전 증분 foodo_something()이라고 부르기 원했습니다.

5

의 차이 :

Number& Number::operator++() { 
    ++value_; 
    return *this; 
} 

Number Number::operator++() { 
    ++value_; 
    return *this; 
} 

은, 당신이 첫 번째 코드, 다음 식을 사용하는 경우 :

++(++(++someNum)); 

증가 someNum 세 번을. 여기에 출력을 참조 : http://ideone.com/y9UlY

그러나 두 번째를 사용하는 경우,이

++(++(++someNum)); 

증가 someNum 단 한 번! 여기에 출력을 참조하십시오 : 당신은 두 번째와 세번째 operator++()에서 참조를 반환 할 때 ++someNum라는 동일한 개체에 호출하기 때문에, 그것은 동일한 개체, 모든 시간을 증가하기 때문에 http://ideone.com/eOLdj

그것은이다. 그러나 값으로 돌아 오면 두 번째와 세 번째 은 operator++()에서 반환 한 임시 개체 임시 개체를 호출합니다. 따라서 두 번째 및 세 번째 호출은 someNum을 증가시키지 않고 표현식 끝에서 삭제되는 임시 객체를 증가시킵니다.

이제 임시 개체가 파괴되면 왜 처음부터 만들어야합니까? 결국, 사전 증가 연산자는 임시 객체와 원래 객체가 동일한 값을 갖게됨을 의미합니다. 따라서 좋은 디자인 결정은 사전 증가 연산자를 정의 할 때 참조로 돌아와 임시 생성을 피하고 성능을 향상시키는 것입니다.

+0

그래서 두 번째 방법은 후행 증가분과 비교할 때 더 적절합니다. ((someNum ++) ++) ++ 또한 someNum 만 증가시킵니다! 따라서 포스트와 사전 증가 연산자의 의미가 비교 될 수 있기 때문에 사본을 반환하는 것이 더 좋을 것입니다. – mmmmmmmm

+0

@ RüdigerStevens : 사실이 아닙니다. 후행 증분은 정의에 따라 임시로 반환해야합니다. 왜냐하면 반환 된 객체와 원래 객체는 다른 값을 갖기 때문입니다. 그러나 사전 증가의 경우 반환 객체와 원래 객체는 동일한 값을 갖습니다. 따라서 사전 증가 연산자에서 임시를 생성 한 다음 반환하는 것은 중요하지 않습니다. – Nawaz

+0

설명은 좋습니다 ... 링크가 작동하지 않습니다. :) –

관련 문제