【问题标题】:Why access from child class to the field of other exemplar of superclass crashed this field?为什么从子类访问超类的其他示例字段会导致该字段崩溃?
【发布时间】:2025-12-11 10:15:02
【问题描述】:

在第二个扩展类中,当调用方法时,字段的克隆值正在发生变化。

上市:

#include<iostream>
using namespace std;
class Set
{
public:
    Set(int min,int max)
    {
        num_bits=max-min+1;
        num_bytes=(num_bits+7)/8;
        elems=new int8_t[num_bytes];
        for(int i=0; i<num_bytes; i++)elems[i]=0;
        minElem=min;
        maxElem=max;
    };

    void add(int n)
    {
        int bit=n-minElem;
        elems[bit/8]|=(1<<(bit%8));
    };

    void del(int n)
    {
        int bit=n-minElem;
        elems[bit/8]&=~(1<<(bit%8));
    };

    bool has(int n)
    {
        int bit=n-minElem;
        return(elems[bit/8]&(1<<(bit%8)));
    }

    void print()//str
    {
        int i=0;
        do
        {
            cout<<(has(i+minElem)?"1":"0");
            i++;
            if(i%8==0)cout<<" ";
        }
        while(i<num_bits);
    }

    ~Set()
    {
        delete[] elems;
    };

public://rotected
    int num_bits,num_bytes,minElem,maxElem;
    int8_t *elems;
};

class ExSet:public Set{
    public:
    ExSet(int min,int max):Set(min,max){}
    ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
    void clone(Set s){
    //for(int i=0;i<num_bytes;i++){int x=s.elems[i];cout<<elems[i]<<'='<<s.elems[i]<<'/';}
    };
};

main()
{
    char *p="ABCZabxyz";
    Set s('A','z');
    do s.add(*p);
    while(*++p!='\0');
    s.del('B');
    s.print();
    cout<<endl;
    for(char c='A'; c<='z'; c++)if(s.has(c))cout<<c;
    cout<<endl;
    //delete &s;
    ExSet es(s);
    for(char c='A'; c<='z'; c++)if(s.has(c))cout<<c;
};

预期:

10100000 00000000 00000000 01000000 11000000 00000000 00000001 11
ACZabxyz
ACZabxyz

获取:

10100000 00000000 00000000 01000000 11000000 00000000 00000001 11
ACZabxyz
FGINQRVWghqrvw

【问题讨论】:

  • 阅读Rule of Three,并通过引用传递复杂对象,除非您特别想复制它们。
  • 这是正确的详细信息:
    创建子 ExSet es(s) 时;字段的值正在改变。如果我切断 I//ExSet es(s);我看到了预期。

    无法编辑我的帖子,编辑要求更多细节不可阻挡((

标签: c++ class inheritance superclass


【解决方案1】:

您正在复制对象而没有指定自定义复制构造函数。这失败了,因为您的 Set 类有一个指向堆对象的成员。该堆对象必须由客户复制构造函数复制,因为编译器提供的复制构造函数没有正确复制它。

阅读有关定义复制构造函数以及深度副本与平面副本的信息。

【讨论】:

    【解决方案2】:

    下面这行是你的记忆问题的根源。

    ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
    

    当你执行时

    ExSet es(s);
    

    在调用ExSet 的构造函数时会生成s 的临时副本。当该临时对象被破坏时,它会删除elems 持有的内存。

    s被破坏时,同样的内存被再次删除。这会导致未定义的行为。在您的情况下,它会产生错误的结果。在其他情况下,程序可能会崩溃。

    您可以通过使用解决此特定问题

    ExSet(Set const& s):Set(s.minElem,s.maxElem){/*clone(s);*/}
    

    但是,为了进行适当的修复,请在 Set 中提供一个复制构造函数和一个复制赋值运算符。要了解原因,请查看Rule of Three

    【讨论】:

      【解决方案3】:

      我认为你的问题在这里:

      ExSet(Set s):Set(s.minElem,s.maxElem){/*clone(s);*/}
      

      当你调用Set的构造函数时,你分配了新的数组:

      elems=new int8_t[num_bytes];
      

      并丢失指向先前数据的指针。 您应该创建一个适当的复制构造函数或更改现有的。

      【讨论】:

        最近更新 更多