重载=运算符悖论

时间:2012-09-29 20:08:49

标签: c++ operator-overloading

所以说我有

Class Person{
private:
    Person* _friends[10];
public:
//All methods listed below. Except for the main one, that is.
}
Person::Person()
{
    for(int i=0; i < 10; i++)
        _friends[10] = 0;
}
Person* Person::getFriends()
{
    return _friends;
}
void Person::addFriend(Person* buddy) //Assume it's fully functional.
{
    //code for adding a friend.
}
void Person::operator=(Person& p)
{
    for(int i = 0; i < 10; i++)
        _friends[i] = p.getFriends()[i];
}

int main()
{
    int user1size = 10;
    int user2size = 30;
    Person* user1 = new Person[10];
    Person* user2 = new Person[10];

    //assume these 4 next lines will be repeated with different values a few more times, in more intricate ways, by the magic of for/while loops.
    user1[0] = new Person();
    user2[9] = new Person();
    user1[0].addFriend(user[9]);
    user1[9].addFriend(user[0]); 

    for(int i = 0; i < user1size; i++)
    {
        user2[i] = user1[i]; //Here is where the paradox starts.
    }

    delete [] user1;
return 0;
}

那么,我的问题是它停在哪里?我的意思是,我的意图是只复制对_friends数组中Person对象的引用,但我明白这可能很少甚至不可能,所以解决方案是继续“复制”这些Person对象,而这些对象又有一个朋友列表,这些朋友也有朋友等。我知道它必须停在某个地方,但我并不是真的希望它一直都能完成,甚至不提我不希望某些Person对象被过度复制或陷入无限循环。 那么如何解决这个悖论?

P.S。 :请理解我的代码是否有很多错误或是蹩脚的。我在旅途中做到了,所有我打算用它来让你们都抓住这个大概。

P.S.2:除了<ostream>之外,我不能使用任何其他库,对我来说很糟糕。

P.S.3:你可以提供我阅读的任何网站/文章都会让我很开心!先谢谢你。

3 个答案:

答案 0 :(得分:3)

嗯,首先,您可能想要做的只是按原样复制指针。

为什么呢?因为如果有人&#34; A&#34;有一个朋友&#34; F&#34;和一个人&#34; B&#34;有朋友&#34; F&#34;同样,他们可能会指同一个人&#34; F&#34;宾语。如果您按照建议制作了一份深层复制品,并将A复制到A2,将B复制到B2,那么您将共有三个不同的人,即#34; F&#34;对象 - 从A和B引用的原始对象,从A2引用的副本,以及从B2引用的另一个副本。

当然,这可能是你想要的;我不知道。但在许多情况下,它不是。

整个指针设置都可以正常工作,尽管您必须小心内存管理:您可以轻松地找到指向不再存在的人的指针

如果您确实想要进行深层复制(&#34;深层复制&#34;也是复制引用对象的副本),您必须自己查找周期,例如通过跟踪哪些对象你已经复制了。我现在不想尝试这样的事情,因为它可能会变得有些复杂,我不认为你真的想要深刻复制你的人物#34;对象。

答案 1 :(得分:1)

没有悖论,因为你没有做深刻的复制。看看这个声明:

Person* _friends[10];

这表示_friends是一个指针Person个对象的数组。正确复制operator=()此数组将在数组中的每个operator=()上调用Person

但是,以下函数将无法编译:

Person* Person::getFriends()
{
    return _friends;
}

返回类型和_friends的类型不匹配。这就是为什么发布编译并准确再现您遇到的问题的代码非常重要的原因。

答案 2 :(得分:0)

IIUC,您想知道如何处理对象图的副本,并且您希望在图中保持它们的连接。让我们说乔有一个朋友比尔和比尔有一个朋友乔,你复制乔(让我们命名副本乔'),你想乔也有一个朋友(反身)乔'作为朋友。编程编译器时通常会出现此问题。

实际执行此操作的最简单方法是永远不要复制任何副本。让对象驻留在它们的内存位置,一直使用它们的引用/指针并破坏性地修改它们。

但是,有时需要复制对象,可能需要修改图形(在编译器场景中,可能意味着例如内联函数)。在这种情况下,您使用简单的图遍历算法DFS,大致如下:

// o will be the object to copy
// m will be a map (old object -> new object)
copy(object* o, map& m) {
  if(m.contains(o))
    return m[o];
  object* n = allocate new object;
  m[o] = n; // set the map beforehand, in case we have some back edges from this subtree
  n.subobject = copy(o.subobject, m); // for each subobject, or relation. In your case, friend
  return n;
}

如果您只想将某个对象移动到新位置,您只需遍历整个图形并覆盖指针即可。如果您的图表中也有后边缘(例如,不仅是“朋友”,还有“我的朋友是谁”),这就容易多了。不过,最好的选择是避免它;这意味着不会创建可能会增长并生成Person个数组的Person*数组,以便真正的Person仍然保留在同一个内存位置。