2015-02-06 2 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

Ваш вопрос очень интересный.

Прежде всего, ваш код не работает из-за slicing: у вас есть два объекта Subclass, но компилятор считает, что одна из него лишь Class. Таким образом, генерируемый код копирует только часть данных .

Чтобы продемонстрировать это, давайте ellaborate на первоначальном экстракте кода gha.st «S:

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() для клонирования объекта (объект должен знать свой собственный тип) в цель, если цель имеет тот же тип.
Тогда вы можете определить operator=() для Class, чтобы использовать это clone(). Это делает его удобным для использования, но недостатком является то, что вы больше не сможете использовать operator= по умолчанию для любого потомка 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

Смежные вопросы