所以问题如下:
我们有这样的课程:
class Boo : public SuperBoo {
Foo* fFoo1;
Foo* fFoo2;
// ...
}
,其中foo是一个单形类。现在我们需要为这个类重载赋值运算符(=)。
答案 0 :(得分:2)
class derived : public base {
public:
double *b;
derived(double aParam, double bParam) : base(aParam) {
b = new double; *b = bParam;
}
derived() : base() {
b = new double; *b = 0; }
~derived() {
delete b;
}
derived(const derived &derivedParam) : base(derivedParam) {
b = new double; *b = *derivedParam.b;
}
void show() {
cout << *a << " " << *b << endl;
}
derived &operator=(const derived& derivedParam) {
*a = *derivedParam.a; *b = *derivedParam.b; return *this;
}
};
int main(){
base *ptrB1, *ptrB2;
derived objD1(5,6), objD2;
ptrB1 = &objD1;
ptrB2 = &objD2;
*ptrB2 = *ptrB1;
ptrB2->show();
return 0;
}
答案 1 :(得分:1)
由于你有两个指针作为数据成员,你需要有一个重载的赋值运算符(以及一个析构函数和一个复制构造函数),以便在赋值的情况下制作指针的深层副本
Boo::operator=( const Boo& obj) {
Superboo::operator=obj //calling the assignment operator of the base explicitly
fFoo1 = obj->fFoo1;
fFoo2 = obj->fFoo2;
return *this;
}
现在,由于Boo继承自SuperBoo,您必须显式调用基类Superboo的赋值运算符(如果为其定义了非默认赋值运算符。)
答案 2 :(得分:1)
通常,当您拥有类层次结构时,通常谨慎不提供赋值运算符。事实上,通常最好防止分配和复制构造:
class Example
{
// ...
private:
Example(Example const &);
Example &operator=(Example const &);
};
或者在C ++ 11中:
class Example
{
// ...
Example(Example const &) = delete;
Example &operator=(Example const &) = delete;
};
赋值运算符通常用于值类,而不适用于具有标识的类。在你的例子中,名字并没有告诉我们什么,真的。但是,如果您的Boo
实际上类似于GuiWidget
,Driver
,FileStream
或ThreadWrapper
,即面向对象编程实际上可能有用的东西,那么任务的概念不再有意义。将一个GuiWidget
分配给另一个GuiWidget
是什么意思,或者为了更精确的示例,将一个按钮分配给下拉菜单是什么意思?
分配对于未引用其他资源的类非常有用,例如Matrix
,Color
,List
或PostalAddress
。将一个Matrix
分配给另一个Matrix
或者将蓝色对象分配给红色对象当然是有意义的。
查看标准库。您会注意到像std::ifstream
这样的面向对象的类不支持赋值,而像std::list
这样的值类则支持赋值。
您希望支持面向对象类的分配可能有以下两个原因之一:
你想支持赋值,因为“它很自然,每个C ++类都应该拥有它”。那是错的。
当你“分配”时,你想要一些特殊的东西。在上面的示例中,当向下拉菜单“分配”按钮时,您可能只想给下拉菜单提供与按钮相同的颜色。这是一个有效的愿望,但operator=
只是一个错误的(即误导性的,令人困惑的)函数名称。你最好将这个函数命名为AssignStyleFrom
,并禁止赋值。
通过阻止面向对象类的分配,您还可以避免所有令人讨厌的问题以及随之而来的混乱。在Scott Meyers的 Effective C ++ (或者它是更有效的C ++ ?)中,有一整章关于类层次结构中赋值运算符的缺陷。通过设计程序使得赋值运算符仅由不可导出的值类提供,您不再需要担心这些事情。