为什么从子类访问其他超类范例的字段崩溃了这个字段?

时间:2014-10-27 17:42:42

标签: c++ class inheritance superclass

在第二个扩展类中,当调用方法clone(s)的字段值正在改变时。

清单:

#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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

我认为你的问题在这里:

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

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

elems=new int8_t[num_bytes];

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

答案 2 :(得分:0)

以下行是您的记忆问题的来源。

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

执行时

ExSet es(s);

s的临时副本是在ExSet的构造函数的调用中创建的。当该临时值被破坏时,它会删除elems所拥有的内存。

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

您可以使用

解决此特定问题
ExSet(Set const& s):Set(s.minElem,s.maxElem){/*clone(s);*/}

但是,要获得正确的修复,请在Set中提供复制构造函数和复制赋值运算符。要了解原因,请查看Rule of Three