2010-07-09 5 views
0

다음 문제를 해결하는 방법에 대해 매우 혼란스러워합니다.연산자 = 하위 클래스

class Foo 
{ 
    public: 
     // this only copies the data 
     Foo& operator=(const Foo& foo); 

     // do something that computes a new Foo from *this 
     Foo modifiedFoo(); 

    //.. 
    private: 
     std::vector<int> data; 
} 

class Bar: public Foo 
{ 
    public: 
     void someNewMethod(); 
    //.. 
    // no new data 
} 

상속 이제 경우 bar1 = bar2의 연산자 = 옳은 일을한다는 것을 보장 :

우리가 클래스는 기본 연산자와 데이터 만 같은 간단한 벡터를 정의하고 상속 된 클래스에서만 추가 메소드를 추가 말해봐 . 는 그러나보기의 데이터 지점에서 모두 BarFoo은 기본적으로 동일, 그래서 모두

Foo foo; 
Bar bar; 

foo = bar; // this ... 
bar = foo; // .. and this; 

을 쓸 수보다 구체적으로

bar = foo.modifiedFoo(); 

[ 편집하고 싶습니다 : 그리고 BTW,이 작동하지 않습니다 중 하나를 분명 ...

bar1 = bar2.modifiedFoo(); 

]

가 나는 Bar 다른 Bar& operator=(const Foo & foo)을 추가하는 등 쉬운 것이라고 생각하지만, 어떻게 든이는 무시된다 (그리고 나는 점점 더 많은 클래스를 파생하는 경우? 무엇을, 어쨌든이 마음에 들지)

가 그래서입니다 이것에 대해 갈 올바른 방법 ??

감사합니다. 그리고 이것이 전에 물어 보면 미안합니다.

+0

없음 복사 생성자? 대입 연산자가 있다면 그 중 하나가 필요하다고 생각했습니다. – John

+0

@ 존 : 아니, 그렇지 않으면, 하나가 아닌 다른 것을 제공 할 이유는 거의 없지만. 복사 구성 및 스왑의 관점에서 복사 할당을 구현하는 것은 쉽지만 그 반대의 경우는 아닙니다. –

+0

@ 존 : 거기에 // ...;) – bbtrb

답변

1

Martin told you what went wrong, 여기 당신이 대신해야 할 일이다 파생 된 클래스의. 그러나

bar = foo; 

는 (적어도 암묵적으로) 작동하지 않습니다 그것은 안된다. 여기에서하려고하는 것은 기본 클래스 객체 (또는 참조)를 파생 클래스에 할당하는 것입니다.
그러나 파생 클래스는 항상 기본 클래스 개체에 사용할 수 있지만 그 반대는 사실이 아닙니다. 당신이 필요로하는 것은 보트 경우 모든 차량이 배이기 때문에 (당신은 아무 생각없이, 당신이 차 일과 '수 사용하고있는 차량을 어떤 차량을 사용할 수 없습니다 d 익사)

이것은 작동하지 않는다고 말하는 것은 아닙니다. 기본 클래스 객체에서 파생 클래스 객체를 만드는 방법을 알고 있다면 그렇게하는 함수를 작성할 수 있습니다. 컴파일러가 자동차차량에서 만드는 법을 모르는 것입니다.

solipist has shown으로, 이러한 변환 함수는 생성자가 될 수 있습니다. 그러나, 나는 변환 생성자는 명시 적으로 만들 것 :

class Bar: public Foo 
{ 
    public: 
     explicit Bar(const Foo&); 
    // 
} 

explicit 키워드는 컴파일러가 당신이 그렇게 말하지 않는 한이 생성자를 호출하려고 시도하지 않습니다 있는지 확인합니다.

//void f(Foo); // you meant to call this, but forgot to include its header 
void f(Bar); // you didn't even know this was included 

Foo foo; 
f(foo); // won't compile with the above Bar class 

을 컴파일러는 자동으로이 코드를 생성하는 것입니다 : 당신이 그것을 제거하는 경우,이 코드를 컴파일 할이 처음에 편리한 것 같지만 f(Bar(foo));
을, 나는 조만간 모든 하나의 암시에 의해 물린 생각 전환 내 코드로 들어가서 나중에 제거해야했습니다. 수년 전 나는 결코 더 이상 그들을 용납하지 않을 것이라고 맹세했다. 심지어 explicit 변환 생성자는 여전히 Foo 객체 f(Bar)를 호출 할 수 있습니다
주 - 당신은 그냥이 이렇게 명시 적으로 말 :

f(Bar(foo)); // compiles fine even with the explicit conversion constructor 
4

이것은 슬라이싱 문제로 알려져있다 : 그것은 단지 푸 인 것처럼

foo = bar; 

는 기본적으로 바 객체가 사용됩니다.
그러면 bar의 Foo 부분이 foo 객체에 복사됩니다 (따라서 Bar라는 지식이 사라집니다).

컴파일러가 클래스에 대한 대입 연산자를 자동으로 정의하기 때문입니다. 다음은 유효하지 않습니다

bar = foo; 

여기 컴파일러는 바 타입의 '바'이며 할당 연산자를 찾습니다 본다. 컴파일러가 'Bar'에서 컴파일러를 생성하고이를 적용하려고 시도합니다 (Foo에서 현재 숨겨져 있음). 컴파일러에서 생성 된 할당 연산자는 다음과 같습니다.

Bar& operator=(Bar const& rhs) 

따라서 위의 행은 일치하지 않으며 할당에 실패합니다.

+0

좋아, 이것은 내가 생각했던 것 거의 같다. 그래서 뭐 할까? – bbtrb

+0

문제 도메인에 대해 더 알지 못해도 대답하기가 어렵습니다. –

+0

내가 정말로 원하는 것은'Foo'를 사용자로부터 숨기는 것입니다. 모든 것은'Bar'를 통해 이루어져야합니다. 그러므로 나는'Bar modifiedFoo()'와 같은 것을 'Bar'에 넣고,'Foo modifiedFoo()'의 구현을 오버 헤드없이 (캐스팅 할 때 vector <>의 복사본으로) 재사용하고 싶습니다. – bbtrb

0

FooBar으로 암시 적으로 캐스팅하려면 비표 시형 생성자를 만듭니다. 당신이 '바 = foo는'쓸 때

class Bar: public Foo 
{ 
    public: 
     Bar(const Foo&); 
    // 
} 

는 이제 Foo는 암시 적으로 임시 Bar으로 캐스팅, 그래서 Bar 할당 연산자를 성공적으로 사용할 수 있습니다.개체를 참조

Bar bar; 
Foo& foo = bar; // this works now 

지금 foo는 객체에 대한 참조, 당신은 (BTW, 포인터) 기본 클래스 참조를 가질 수 있습니다

+2

묵시적 캐스팅은 싫은 이유가 있습니다. – sbi