c ++赋值运算符=用派生类重载
c++ assignment operator= overloading with derived classes
我目前正在编写一个复杂的 class,在其中我基本上需要复制一个派生的 classes 列表。简化版如下:
我有一个基础 class,我从中派生出其他几个 classes:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual Base& operator=(const Base& rhs)
{
cout << "Base=" << endl;
return *this;
}
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
A& operator=(const A& rhs)
{
cout << "A=" << endl;
return *this;
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
B& operator=(const B& rhs)
{
cout << "B=" << endl;
return *this;
}
};
然后我创建一个对象列表,我将其保存在 Base 的指针列表中 class:
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
然后我想将这些对象复制到具有相同 classes(相同顺序)但可能具有不同值的第二个列表中。
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
但是 c++ 无法做到这一点。因为列表的类型为 Base*,所以取消引用会创建一个 Base 类型的对象。因此调用 Base class 的赋值运算符 = 而不是派生 class 中的正确赋值运算符。我该如何解决这个问题?
或者我如何告诉 C++ 使用正确的运算符?也许通过一些 isinstanceof-function?
有关完整示例,请参阅:
int main()
{
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
vector<Base*> listB;
new Base(&listB);
new A(&listB);
new B(&listB);
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]).test();
}
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
}
输出:
Base
A
B
Base=
Base=
Base=
这里有一些误解。首先,将派生 class 的实例分配给基础 class 的实例是什么意思?让我们采用一个简单的层次结构:
struct A { int x; };
struct B : A { int y; };
A a;
B b;
a = b; // what should this do?
b = a; // what about this?
对于普通的 C++,第一个 object slicing,第二个是病式的。但即使是第一个,格式良好,通常也不是您想做的。您确定要切片吗?
第二个是当您将赋值运算符设为虚拟时:
virtual Base& operator=(const Base& rhs)
None 的派生 classes 实际上覆盖了它。 A
的赋值运算符采用 A const&
,B
的赋值运算符采用 B const&
。如果你用 override
标记这两个,你的编译器会向你指出这一点。如果您将这两个修复为采用 Base const&
参数,那么您将得到您想要打印的内容 - 但它可能仍然不是您真正想要发生的事情。
为了真正制作多态拷贝,一个典型的解决方案是提供一个虚拟克隆方法:
virtual Base* clone() const = 0;
您派生的 classes 实现:
struct A : Base {
A* clone() const override { return new A(*this); }
};
然后使用clone()
代替赋值。这里不会有切片。
在此处插入有关内存管理和原始指针的常见注意事项。
好的。我找到了解决问题的方法。我实现了一个以 Base class 作为参数的复制函数。在这个复制函数中,我可以使用 pointa
复制变量。 classe 现在如下:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual void clone(Base* pointer) = 0;
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
A* pointa = (A*)pointer;
cout << "clone A" << endl;
//Clone Variables here
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
B* pointa = (B*)pointer;
cout << "clone B" << endl;
//Clone Variables here
}
};
这意味着我现在可以通过以下方式复制对象:
for (int i = 0; i < (int)listA.size(); i++)
{
listA[i]->clone(listB[i]);
}
但是这个解决方案在任何方面都不是类型安全的,这是我想要满足的要求。我研究了我的想法,并决定在没有列表的情况下手动执行操作,这意味着有很多重复的代码,但让我省心。
我目前正在编写一个复杂的 class,在其中我基本上需要复制一个派生的 classes 列表。简化版如下: 我有一个基础 class,我从中派生出其他几个 classes:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual Base& operator=(const Base& rhs)
{
cout << "Base=" << endl;
return *this;
}
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
A& operator=(const A& rhs)
{
cout << "A=" << endl;
return *this;
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
B& operator=(const B& rhs)
{
cout << "B=" << endl;
return *this;
}
};
然后我创建一个对象列表,我将其保存在 Base 的指针列表中 class:
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
然后我想将这些对象复制到具有相同 classes(相同顺序)但可能具有不同值的第二个列表中。
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
但是 c++ 无法做到这一点。因为列表的类型为 Base*,所以取消引用会创建一个 Base 类型的对象。因此调用 Base class 的赋值运算符 = 而不是派生 class 中的正确赋值运算符。我该如何解决这个问题?
或者我如何告诉 C++ 使用正确的运算符?也许通过一些 isinstanceof-function?
有关完整示例,请参阅:
int main()
{
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
vector<Base*> listB;
new Base(&listB);
new A(&listB);
new B(&listB);
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]).test();
}
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
}
输出:
Base
A
B
Base=
Base=
Base=
这里有一些误解。首先,将派生 class 的实例分配给基础 class 的实例是什么意思?让我们采用一个简单的层次结构:
struct A { int x; };
struct B : A { int y; };
A a;
B b;
a = b; // what should this do?
b = a; // what about this?
对于普通的 C++,第一个 object slicing,第二个是病式的。但即使是第一个,格式良好,通常也不是您想做的。您确定要切片吗?
第二个是当您将赋值运算符设为虚拟时:
virtual Base& operator=(const Base& rhs)
None 的派生 classes 实际上覆盖了它。 A
的赋值运算符采用 A const&
,B
的赋值运算符采用 B const&
。如果你用 override
标记这两个,你的编译器会向你指出这一点。如果您将这两个修复为采用 Base const&
参数,那么您将得到您想要打印的内容 - 但它可能仍然不是您真正想要发生的事情。
为了真正制作多态拷贝,一个典型的解决方案是提供一个虚拟克隆方法:
virtual Base* clone() const = 0;
您派生的 classes 实现:
struct A : Base {
A* clone() const override { return new A(*this); }
};
然后使用clone()
代替赋值。这里不会有切片。
在此处插入有关内存管理和原始指针的常见注意事项。
好的。我找到了解决问题的方法。我实现了一个以 Base class 作为参数的复制函数。在这个复制函数中,我可以使用 pointa
复制变量。 classe 现在如下:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual void clone(Base* pointer) = 0;
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
A* pointa = (A*)pointer;
cout << "clone A" << endl;
//Clone Variables here
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
B* pointa = (B*)pointer;
cout << "clone B" << endl;
//Clone Variables here
}
};
这意味着我现在可以通过以下方式复制对象:
for (int i = 0; i < (int)listA.size(); i++)
{
listA[i]->clone(listB[i]);
}
但是这个解决方案在任何方面都不是类型安全的,这是我想要满足的要求。我研究了我的想法,并决定在没有列表的情况下手动执行操作,这意味着有很多重复的代码,但让我省心。