2015-02-06 7 views
4

먼저, 일부 하위 클래스가있는 클래스에서 대입 연산자를 정의 할 수 없습니다. 우리가 Subclass1 = Subclass2을 가능하게하고 싶지 않기 때문이라고 생각합니다.추상 클래스로 "슬라이스"하면 어떻게됩니까

하지만 Class은 추상적 인 클래스이고 Subclass은 ... 알고 있습니다. 그렇다면 이것과 같은 것을 할 수 있습니까?

Class* p = new Subclass; 
Subclass s1; 
*p = s1; 

는 사실, 난 내 코드에서 그 구현을 시도했지만 작동하지 않았다 : 당신이 도와 주 시겠어요?

내 전체 코드 :

#include <cstdlib> 
#include <iostream> 
#include <typeinfo> 

using namespace std; 

class BadIndex{ 
    int index; 
public: 
    BadIndex(int i):index(i){} 
    int getIndex(){ return index; } 
}; 

template <typename t> 
class Wielomian{ 
public: 
    ~Wielomian(){} 
    virtual int getDeg() = 0; 
    virtual t& operator [](int) = 0; 
    virtual bool operator ==(Wielomian<t>&) = 0; 
    virtual Wielomian<t>& operator +(Wielomian<t>&) = 0; 
    virtual Wielomian<t>& operator +=(Wielomian<t>&) = 0; 
}; 

template <typename t> 
class TabWiel: public Wielomian<t>{ 
    int deg; 
    t* plnml; 
public: 
    TabWiel(t tab[] = {}, int size = 0); 
    ~TabWiel(); 
    TabWiel(const TabWiel<t>&); 
    TabWiel<t>& operator =(const TabWiel<t>&); 

    template <typename st> 
    friend ostream& operator <<(ostream& s, TabWiel<st>& tw);            
    int getDeg(){ return deg; } 
    t& operator [](int); 
    bool operator ==(Wielomian<t>&); 
    TabWiel<t>& operator +(Wielomian<t>&); 
    TabWiel<t>& operator +=(Wielomian<t>&); 
}; 

template <typename t> 
TabWiel<t>& TabWiel<t>::operator =(const TabWiel<t>& tw){ 
    if (this != &tw){ 
     delete[] plnml; 
     deg = tw.deg; 
     plnml = new t[deg + 1]; 
     for (int i = 0; i < deg + 1; i++) 
      plnml[i] = tw.plnml[i]; 
    } 
    return *this; 
} 

template <typename t> 
TabWiel<t>::TabWiel(t tab[], int size){ 
    deg = size - 1; 
    plnml = new t[deg + 1]; 
    for (int i = 0; i < deg + 1; i++) 
     plnml[i] = tab[i]; 
    if (deg == -1){ 
     deg = 0; 
     plnml[0] = 0; 
    } 
} 

template <typename t> 
TabWiel<t>::~TabWiel(){ 
    delete[] plnml; 
} 

template <typename t> 
TabWiel<t>::TabWiel(const TabWiel<t>& tw){ 
    deg = tw.deg; 
    plnml = new t[deg + 1]; 
    for (int i = 0; i < deg + 1; i++) 
     plnml[i] = tw.plnml[i]; 
} 

template <typename t> 
t& TabWiel<t>::operator [](int s){ 
    if (s >= 0 && s < deg + 1) 
     return plnml[s]; 
    else 
     throw BadIndex(s); 
} 

template <typename t> 
bool TabWiel<t>::operator ==(Wielomian<t>& tw){ 
    try{ 
     TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw); 
     if (deg == rhs.deg){ 
      for (int i = 0; i < deg + 1; i++){ 
       if (plnml[i] != rhs.plnml[i]) 
        return false; 
      } 
      return true; 
     } 
     return false; 
    } 
    catch (const bad_cast& e){ 
     cerr << "An exception" << e.what() << " thrown." << endl; 
    } 
} 

template <typename t> 
ostream& operator <<(ostream& s, TabWiel<t>& tw){ 
    for (int i = 0; i < tw.deg + 1; i++){ 
     if (i != tw.deg) 
      s << tw.plnml[i] << "x^" << i << "+"; 
     else 
      s << tw.plnml[i] << "x^" << i << endl; 
    } 
    return s; 
} 

template <typename t> 
TabWiel<t>& TabWiel<t>::operator +(Wielomian<t>& tw){ 
    try{ 
     TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw); 
     if (rhs.deg <= deg){ 
      for (int i = 0; i < rhs.deg + 1; i++) 
       plnml[i] = plnml[i] + rhs.plnml[i]; 
      return *this; 
     } 
     else{ 
      t* tmp = new t[deg + 1]; 
      for (int i = 0; i < deg + 1; i++) 
       tmp[i] = plnml[i]; 
      int tmp_deg = deg; 
      delete[] plnml; 
      deg = rhs.deg; 
      plnml = new t[deg + 1]; 
      for (int i = 0; i < deg + 1; i++){ 
       if(i < tmp_deg + 1) 
        plnml[i] = tmp[i] + rhs.plnml[i]; 
       else 
        plnml[i] = rhs.plnml[i]; 
      } 
      return *this; 
     } 
    } 
    catch (const bad_cast& e){ 
     cerr << "An exception" << e.what() << " thrown." << endl; 
    } 
} 

template <typename t> 
TabWiel<t>& TabWiel<t>::operator +=(Wielomian<t>& tw){ 
    try{ 
     TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw); 
     TabWiel<t>* nowy = new TabWiel<t>; 
     TabWiel<t> copy; 
     copy = *this; 
     *nowy = copy + rhs; 
     return *nowy; 
    } 
    catch (const bad_cast& e){ 
     cerr << "An exception" << e.what() << " thrown." << endl; 
    } 
} 

나는 일을 비어 있지 않은 서브 클래스 객체에 *p의 할당을 기원합니다. 그러나 모든 코드는 "Wielomian"정의를 입력 한 다음 main 함수의 다음 줄로 진행합니다 (이 경우는 마지막 줄입니다).

+2

"작동하지 않았다"는 것은 무엇을 의미합니까? 오류 메시지가 나타 났습니까? 컴파일을 거부 했습니까? –

+0

나는 아무것도하지 않았다. 디버거를 실행하고 한 줄씩 따라했습니다. 방금 초록의 클래스 정의에 들어갔다. – Jules

+0

어떤 행동을 기대 했습니까? –

답변

2

귀하의 질문은 매우 흥미 롭습니다. 당신이 Subclass의 두 개체가 있지만 컴파일러는 하나 만 Class이라고 생각 : 모든

먼저, 코드 때문에 slicing 작동하지 않습니다. 따라서 생성 된 코드는 데이터의 공통 부분 인 만 복사합니다. 이를 설명하기 위해

,의는 gha.st의 초기 코드 추출물에 ellaborate 보자

struct Class { int a; virtual void hugo() = 0; }; 
struct Subclass : Class { int b; void hugo() override { cout<<"sub"<<a<<b<<endl; } }; 
int main() { 
    Class* p = new Subclass; 
    static_cast<Subclass*>(p)->a = 2; 
    static_cast<Subclass*>(p)->b = 3; 
    Subclass s1; 
    s1.a = 4; s1.b=5; 
    *p = s1; // slicing !! 
    p->hugo(); 
    return 0; 
} 

은 무엇 여기됩니까? 글쎄, b 회원은 *p이 (가) Subclass인데도 복사되지 않았습니다!

그러나 *p은 여전히 ​​Subclass이므로이 작업을 수행하기 위해 다형성을 사용할 수 있습니다. 목표는 동일한 유형 인 경우 가상의 clone() 구성원을 사용하여 개체 (개체가 자체 유형을 알아야 함)를 대상으로 복제하는 것입니다.
그런 다음 Classoperator=()을 지정하면 clone()을 사용할 수 있습니다. 이 방법을 사용하면 편리하지만 단점은 무한 재귀를 피하려는 경우 더 이상 이 의 하위 집합에 속해 Class이 될 수 없다는 것입니다.

struct Class { 
    int a; 
    virtual void hugo() = 0; 
    virtual bool clone(Class*t) = 0; 
    Class& operator=(Class& o) { 
     if (!o.clone(this)) { // try to clone on subclass on a target of same subclass 
      // here,the source and target might differ. Only common members can be copied 
      a = o.a; 
     } 
     return *this; 
    } 
}; 
struct Subclass : Class { 
    int a,b; 
    void hugo() override { cout<<"sub"<<a<<b<<endl; } 
    bool clone(Class*t) { 
     cout<<"Clone "; 
     if (dynamic_cast<Subclass*>(t)) { // if source and target of same subclass 
      //*dynamic_cast<Subclass*>(t) = *this; // this doesn't work cause default operator will try to copy the Class base, causing recursion 
      dynamic_cast<Subclass*>(t)->a = a; // copy members 
      dynamic_cast<Subclass*>(t)->b = b; 
      return true; 
     } 
     else return false; // or tell that class of source and target are different. 
    } 
}; 

그런 다음 위의 main() 함수를 사용하여 객체가 제대로 복사되는 것을 볼 수 있습니다 여기에

개념의 증거

.

이 트릭은 일종의 double dispatch입니다. 소스 및 타겟 하위 유형에 따라 다양한 종류의 전환을 예측하여 더 자세히 설명 할 수도 있습니다.

+0

정말 고맙습니다. 고마워요! – Jules

관련 문제