c – 如果我“切片”到抽象类会发生什么

首先,我知道赋值运算符不能在具有某些子类的类中定义.我理解这是因为我们不想让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”定义,然后进入主函数的下一行(在我的情况下是最后一行).

最佳答案 你的问题非常有趣.

首先,由于slicing,你的代码不起作用:你有两个Subclass对象,但是
编译器认为其中一个只是一个类.因此生成的代码只复制公共
部分数据.

为了证明这一点,让我们详细说明gha.st的初始代码提取:

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实际上是一个子类!

但是* p仍然是一个子类,所以我们可以使用多态来实现这个功能.诀窍是使用虚拟clone()成员进行克隆
如果目标具有相同的类型,则将对象(对象应知道其自己的类型)放入目标中.
然后,您可以为Class定义operator =()以使用此clone().这使得使用起来很方便,但缺点是你将不再使用它
如果你想避免无休止的递归,能够依赖默认运算符=任何类的后代.

这里是概念证明:

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.您甚至可以通过根据源和目标子类型预测各种类型的转换来进一步详细说明.

点赞