怎样做才可以使有虚继承的对象不重复赋值????【大侠一定要帮我】

可见一斑 2012-01-06 07:23:02
比如有这样一个继承关系:
struct Person {
Person& operator=(Person&) {std::cout << "Call Person's operator=!" << std::endl; return *this;}
};
struct Student : public virtual Person {
Student& operator=(Student& other) {Person::operator=(other); std::cout << "Call Student's operator=!" << std::endl; return *this;}
};
struct Teacher : public virtual Person {
Teacher& operator=(Teacher& other) {Person::operator=(other); std::cout << "Call Teacher's operator=!" << std::endl; return *this;}
};
struct Me : public Student, public Teacher {
};

如果调用Me的赋值操作符会间接调用Person的赋值操作符两次!但是由于虚继承的关系每个Me对象只有一个Person部分,这样就发生了重复赋值。
比如:
int main()
{
Me me;
me = me;
}
会输出
Call Person's operator=!
Call Student's operator=!
Call Person's operator=!
Call Teacher's operator=!

这种情况我该怎么办啊?
...全文
188 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
ken_scott 2012-01-09
  • 打赏
  • 举报
回复
想过三个别的办法, 都不行
难点都在于(我们没法区分X::operator=(), 是外部手动调用的, 还是子类Xchild::operator=()内部调用的)
ken_scott 2012-01-09
  • 打赏
  • 举报
回复

A
(v)/ \(v)
B1 B2
\ /
(v) / \ (v)
C1 C2
\ /
D
ken_scott 2012-01-09
  • 打赏
  • 举报
回复
如果不考虑以后产生新的菱形继承的类, 下面代码中的办法应该是可行的
子类都调用菱形最底层(A)的operator=, 并在copy()中调用直接基类的copy(),再修改自己的数据

#include <iostream>

struct A
{
A() : a(0)
{

}

A & operator = (const A & other)
{
if (&other == this) return (*this);
++a; // a = other.a;
std::cout << "A::operator = () !" << std::endl;
return (*this);
}

A & copy(const A & other) // 可以不用
{
// 什么也不做去做!
return (*this);
}

int a;
};

struct B1 : virtual public A
{
B1() : b1(0)
{

}

B1 & operator = (const B1 & other)
{
if (&other == this) return (*this);
A::operator = (other); // (菱形)最底层基类的的operator=
return (copy(other));
}

B1 & copy(const B1 & other)
{
if (&other == this) return (*this); // 1 -- 比较
A::copy(other); // 2 -- 直接基类的copy
++b1; // b1 == other.b1; // 3 -- 自身的修改
std::cout << "B1::operator = () !" << std::endl;
return (*this);
}

int b1;
};

struct B2 : virtual public A
{
B2() : b2(0)
{

}

B2 & operator = (const B2 & other)
{
if (&other == this) return (*this);
A::operator = (other); // (菱形)最底层基类的的operator=
return (copy(other));
}

B2 & copy(const B2 & other)
{
if (&other == this) return (*this); // 1 -- 比较
A::copy(other); // 2 -- 直接基类的copy
++b2; // b2 == other.b2; // 3 -- 自身的修改
std::cout << "B2::operator = () !" << std::endl;
return (*this);
}

int b2;
};

struct C : virtual public B1, virtual public B2
{
C() : c(0)
{

}

C & operator = (const C & other)
{
if (&other == this) return (*this);
A::operator = (other); // (菱形)最底层基类的的operator=
return (copy(other));
}

C & copy(const C & other)
{
if (&other == this) return (*this); // 1 -- 比较
B1::copy(other); // 2 -- 直接基类的copy
B2::copy(other); // 2 -- 直接基类的copy
++c; // c == other.c; // 自身的修改
std::cout << "C::operator = () !" << std::endl;
return (*this);
}

int c;
};

int main()
{
C cc;
std::cout << cc.a << " " << cc.b1 << " " << cc.b2 << " " << cc.c << std::endl;

std::cout << "-------------------" << std::endl;
cc = cc;
std::cout << "-------------------" << std::endl;
std::cout << cc.a << " " << cc.b1 << " " << cc.b2 << " " << cc.c << std::endl;

std::cout << "-------------------" << std::endl;
cc = C();
std::cout << "-------------------" << std::endl;
std::cout << cc.a << " " << cc.b1 << " " << cc.b2 << " " << cc.c << std::endl;

return 0;
}

上面方法如果再引用新的菱形就不行了, 比如
A
(v)/ \(v)
B1 B2
\ /
(v) / \ (v)
C1 C2
\ /
D
再想想有没有好的办法
menzi11 2012-01-08
  • 打赏
  • 举报
回复
楼上的意思上是对的,可是:
"
Person::operator=(*this);
Student::operator=(*this);
Teacher::operator=(*this);

"
Person赋值了两次...不,是三次...



我感觉这个问题基本无解,只能重载me的"=".例如:

"
struct Me : public Student, public Teacher {
Me& operator=(Me& other)
{
std::cout << "Call Person's operator=!" << std::endl;
std::cout << "Call Teacher's operator=!" << std::endl;
std::cout << "Call Student's operator=!" << std::endl;
std::cout << "Call Me's operator=!" << std::endl;
return *this;
}
};

"

然后我觉得2楼说的对,这个应该是设计问题
ri_aje 2012-01-07
  • 打赏
  • 举报
回复
这样行吗?

#include <iostream>
using namespace std;

struct Person {
Person& operator=(Person&x) {std::cout << "Call Person's operator=!" << std::endl; return *this;}
};
struct Student : public virtual Person {
Student& operator=(Student& other) { std::cout << "Call Student's operator=!" << std::endl; return *this;}
};
struct Teacher : public virtual Person {
Teacher& operator=(Teacher& other) { std::cout << "Call Teacher's operator=!" << std::endl; return *this;}
};
struct Me : public Student, public Teacher {
Me& operator=(Me& other)
{
Person::operator=(*this);
Student::operator=(*this);
Teacher::operator=(*this);
std::cout << "Call Me's operator=!" << std::endl;
return *this;
}
};

int main ()
{
Me me;
me = me;
return 0;
}
hzy694358 2012-01-07
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 pathuang68 的回复:]

1. 这是典型的带virtual继承的菱形继承问题。
2. 一个派生类创建对象时,会首先调用其基类的构造函数,这是C++中一个很重要的(或者叫优先级非常高的)原则。在楼主给出的代码中,Student和Teacher都是Me的基类,因此它们的构造函数一定会得到调用,进一步,调用这两类的构造函数之前,他们会分别调用共同的基类Person的构造函数。对于拷贝赋值操作符或者拷贝拷贝构造函数情况与此类似……
[/Quote]
虚继承
平凡的思想者 2012-01-07
  • 打赏
  • 举报
回复
正解。

[Quote=引用 8 楼 pathuang68 的回复:]

1. 这是典型的带virtual继承的菱形继承问题。
2. 一个派生类创建对象时,会首先调用其基类的构造函数,这是C++中一个很重要的(或者叫优先级非常高的)原则。在楼主给出的代码中,Student和Teacher都是Me的基类,因此它们的构造函数一定会得到调用,进一步,调用这两类的构造函数之前,他们会分别调用共同的基类Person的构造函数。对于拷贝赋值操作符或者拷贝拷贝构造函数情况与此类似……
[/Quote]
pathuang68 2012-01-06
  • 打赏
  • 举报
回复
1. 这是典型的带virtual继承的菱形继承问题。
2. 一个派生类创建对象时,会首先调用其基类的构造函数,这是C++中一个很重要的(或者叫优先级非常高的)原则。在楼主给出的代码中,Student和Teacher都是Me的基类,因此它们的构造函数一定会得到调用,进一步,调用这两类的构造函数之前,他们会分别调用共同的基类Person的构造函数。对于拷贝赋值操作符或者拷贝拷贝构造函数情况与此类似
3. virtual继承的作用是在派生类对象中只保留一份拷贝。
qscool1987 2012-01-06
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 mougaidong 的回复:]
引用 5 楼 qscool1987 的回复:

...哎,晕了
原则上多继承的根基类最好不要有数据成员,如果你想阻止第二次赋值也是可以,在根基类赋值函数里面加一个判断,如果有值就直接返回*this,如果没有值就继续赋值嘛


调用赋值操作符以前,永远都是有值的,你的办法不可行。
[/Quote]
对,你说的很对啊,看来只能遵守原则,最好不要有数据成员
turing-complete 2012-01-06
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 qscool1987 的回复:]

...哎,晕了
原则上多继承的根基类最好不要有数据成员,如果你想阻止第二次赋值也是可以,在根基类赋值函数里面加一个判断,如果有值就直接返回*this,如果没有值就继续赋值嘛
[/Quote]

调用赋值操作符以前,永远都是有值的,你的办法不可行。
qscool1987 2012-01-06
  • 打赏
  • 举报
回复
...哎,晕了
原则上多继承的根基类最好不要有数据成员,如果你想阻止第二次赋值也是可以,在根基类赋值函数里面加一个判断,如果有值就直接返回*this,如果没有值就继续赋值嘛
可见一斑 2012-01-06
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 mougaidong 的回复:]
多继承造成了类Me的特殊性,执行两次是合理的

我认为这个问题是属于设计问题,不是语言问题。
[/Quote]
那如果赋值操作符执行了非常复杂的资源管理操作,对同一个部分执行两次完全相同的赋值操作不会出问题吗?
可见一斑 2012-01-06
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 qscool1987 的回复:]
Me(const Me &orig):Student(orig),Teacher(orig),Person(orig)
{
}
复制构造函数这么改下
[/Quote]

这跟复制构造函数有关系吗?
turing-complete 2012-01-06
  • 打赏
  • 举报
回复
多继承造成了类Me的特殊性,执行两次是合理的

我认为这个问题是属于设计问题,不是语言问题。
qscool1987 2012-01-06
  • 打赏
  • 举报
回复
Me(const Me &orig):Student(orig),Teacher(orig),Person(orig)
{
}
复制构造函数这么改下

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧