无法调用指针的打印功能

时间:2014-04-22 07:54:25

标签: c++ pointers visual-studio-2012 inheritance

我一直对我正在做的一些功课感到难过。

我正在研究一个名为“boxFactory”的函数,它将Box基类的指针返回给测试类。然后测试类从该指针调用print函数。

现在我正在尝试在我处理其他类型之前打印方格盒子。但是,当我运行下面的代码时,bptr-> print(os)会抛出一个异常:

“Assignment.exe中0x0091C512处的未处理异常:0xC0000005:访问冲突读取位置0xCCCCCCD0。”

Box * boxFactory(char c, int w, int h){

Box * b;

if(c == 'c')
{
    CheckeredBox cb; 
    b = &cb;
    b->setHeight(h);
    b->setWidth(w);

    return b;
}

return NULL;
}

测试类的代码段:

Box * bptr = boxFactory('c',5,3);

// Check print #7
os.str(""); //reset output holder
bptr->print(os);
t.test(os.str() == "x x x\n x x \nx x x\n", "print 5x3 checkered box from factory");

派生的Checkered类的打印函数:

ostream& CheckeredBox::print(ostream& os) const
{
//HEIGHT for loop
for (int i = 0; i < height_; i++)
{
bool isX; //is current space x or blank

//makes the every other line starts
if (i % 2 == 0) 
{
    isX = true;
}
else
{
    isX = false;
}

//WIDTH for loop
for (int c = 0; c < width_; c++)
{
    if (isX) //utilizes isX boolean
    {
        os << "x";
        isX = false; //oscilates bool between spaces
    }
    else
    {
        os << " ";
        isX = true; //continues oscilation
    }
}

os << "\n"; //append new line after each row
}

return os;

} 

3 个答案:

答案 0 :(得分:3)

您在boxFactory函数中创建了CheckeredBox对象的自动实例。因此,当cb对象超出范围(如果是块)时,它将被销毁,并且您将返回被破坏对象的地址。这就是为什么当您尝试调用此指针的print方法时,会出现“Access Violation”错误。以下是您可以做的事情,以实现您想要的目标。

您需要使用new关键字在堆上构造CheckeredBox对象,然后从boxFactory函数返回它。在这种情况下,您的应用程序将工作,但问题仍然是谁应该删除您在堆上创建的对象。您可以在函数文档中指定调用者应该删除返回的对象,但如果您或其他人使用您的代码不够仔细,则很可能您的应用程序泄漏了内存。 您可以使用std :: auto_ptr来获取和转移对象的所有权,以便自动删除它。

std::auto_ptr<Box> boxFactory(char c, int w, int h){
  std::auto_ptr<Box> b;

  if(c == 'c')
  {
      CheckeredBox *cb = new CkeckeredBox(); 
      cb->setHeight(h);
      cb->setWidth(w);
      b.reset(cb);
  }

  return b;
}

考虑到auto_ptr在新的C ++ 11标准中已弃用,您可以使用boost :: shared_ptr,std :: unique_ptr(仅限C ++ 11)或std :: shared_ptr(仅限C ++ 11)。

答案 1 :(得分:2)

if(c == 'c')
{
  CheckeredBox cb; 
  b = &cb;
  b->setHeight(h);
  b->setWidth(w);

  return b;
}

局部变量在堆栈中分配,当声明它们被声明的代码块退出时,相同的内存空间将用于覆盖它们的其他变量。

要动态分配对象,请使用new运算符,它将分配中的对象。这些对象将在delete之前可用(不要忘记这样做,否则你会得到内存泄漏

b = new CheckeredBox();
// etc.

答案 2 :(得分:1)

您正在返回指向局部变量的指针。这是未定义的行为。

if(c == 'c')
{
    CheckeredBox cb; 
    b = &cb;
    b->setHeight(h);
    b->setWidth(w);

    return b;
}

一旦函数离开此cbif超出范围,但您返回其地址。使用此地址会导致&#34;未定义的行为&#34;。您想要在堆上分配一个对象然后返回它。像下面的东西。

    b = new CheckeredBox();