基类指针数组;每个项目启动我都有不同的结果

时间:2015-12-27 20:24:39

标签: c++ arrays inheritance memory

我有一个创建四个类的任务 - 一个基类,两个派生类和一个可以存储派生对象的动态数组。基类应存储名称(某些字符串),派生应具有其唯一的voice()函数。我的代码是:

#include <iostream>

class Pet
{
public:
    char* name_;
    virtual void voice(){}
};

class Dog : virtual public Pet
{
public:
    Dog(char* str)
    {
        name_ = new char[strlen(str)];
        for(int i=0; str[i] != 0; ++i)
        {
            name_[i] = str[i];
        }
    }
    virtual void voice()
    {
        std::cout<<"I'm a dog! My name is "<<this->name_<<std::endl;
    }
};

class Cat : virtual public Pet
{
public:
    Cat(char* str)
    {
        name_ = new char[strlen(str)];
        for(int i=0; str[i] != 0; ++i)
        {
            name_[i] = str[i];
        }
    }
    virtual void voice()
    {
        std::cout<<"I'm a cat! My name is "<<this->name_<<std::endl;
    }
};

class Pack
{
private:
    Pet** pack_;
    int num;
public:
    Pack()
    {
        pack_ = new Pet*[0];
        num = 0;
    }
    void add(Pet* a)
    {
        Pet** newpack = new Pet*[num+1];
        for (int i = 0; i<num; ++i)
            newpack[i] = pack_[i];
        newpack[num] = a;
        ++num;
        for (int i = 0; i<num; ++i)
            pack_[i] = newpack[i];
        delete [] newpack;
    }
    void voiceall()
    {
        for (int i=0; i<num; ++i)
            pack_[i]->voice();
    }
};

int main() {
    Pack pack;
    for (int i=0; i<6; ++i)
    {
        char* str;
        std::cin.getline(str, 100);
        if (i%2 == 0)
        {
            Dog* a = new Dog(str);
            pack.add(a);
        }
        else
        {
            Cat* a = new Cat(str);
            pack.add(a);
        }
    }
    pack.voiceall();
    return 0;
}

这段代码似乎有用,但令我惊讶的是,不是每次我启动它。三分之一 - 具有相同输入的启动的一半导致错误(EXC_BAD_ACCESS),通常在行voiceall()中的Packpack_[i]->voice();函数中。我在这个基础派生指针的东西上太新了,无法理解什么是错的。

UPD:伙计们,我不能真正使用STL,因为我的老师有非常痛苦的教学方式。

2 个答案:

答案 0 :(得分:1)

pack_ = new Pet*[0];

pack指向大小为0的数组。

++num;

您将num增加到大于0的数字。

for (int i = 0; i<num; ++i)
        pack_[i] = newpack[i];

您可以访问数组越界。这导致了不确定的行为。

要解决这个问题,请不要使用它的界限来访问阵列。您可能打算为此分配一个大小为num且指向pack_的数组。好吧,你确实分配了一个数组,但你永远不会更新pack_所以它的大小永远不会改变,你以后会删除新的更大的数组。我建议使用std::vector来避免这样的错误(作为奖励,它也比你正在做的更有效)。

作为旁注,你有很多内存泄漏。避免手动分配动态内存,并使用std::stringstd::vector轻松修复它们。

答案 1 :(得分:0)

即时崩溃源是您没有为输入分配任何内存 - 您正在读取未初始化的指针。

替换

char* str;

char str[100];

你的名字数组也是一个太小的元素;使用

name_ = new char[strlen(str) + 1];
strcpy(name_, str);

您的add会立即删除存储所有元素所需的数组。
你也可以在旧数组的边界外写字。

应该更像这样:

void add(Pet* a)
{
    Pet** newpack = new Pet*[num+1];
    // Copy the old array to the new.
    for (int i = 0; i<num; ++i)
        newpack[i] = pack_[i];
    // Add the new element to the new array.
    newpack[num] = a;
    ++num;
    delete [] pack_;  // Delete the old array...
    pack_ = newpack;  // ... and use the new one instead.
}