gpt4 book ai didi

c++ - 如果我 "slice"到一个抽象类会发生什么

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:09:35 26 4
gpt4 key购买 nike

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

最佳答案

你的问题很有意思。

首先,由于slicing,您的代码无法正常工作。 : 你有两个 Subclass 的对象,但是编译器认为其中之一只是一个 Class。所以生成的代码只复制常见的部分数据。

为了证明这一点,让我们详细说明 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 实际上是一个 Subclass !

但是 *p 仍然是一个 Subclass,所以我们可以使用多态性来完成这项工作。诀窍是使用一个虚拟的 clone() 成员来克隆如果目标具有相同的类型,则将对象(该对象应知道自己的类型)转换为目标。
然后,您可以为 Class 定义 operator=() 以使用此 clone()。这使得它使用起来很方便,但缺点是你将不再如果您想避免无休止的递归,可以为 Class 的任何后代依赖默认的 operator=

这里是概念验证:

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

关于c++ - 如果我 "slice"到一个抽象类会发生什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28375182/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com