在函数

时间:2016-02-27 00:11:06

标签: c++ oop object

我正在从Java转向c ++,而且当我学习如何在C ++中完成工作时,我有时会感到困惑。我在网上读到,如果在函数内部创建了一个对象,它只存在于函数内部,除非它是使用new声明的。所以我编写了以下代码来测试它:

#include <iostream>
using namespace std;

class Student{
private:
    int ID;
    int score;
public:
    void setID(int num);
    int getID();
    void setScore(int num);
    int getScore();
};
void Student::setID(int num)
{
    ID = num;
}

int Student::getID()
{
    return ID;
}
void Student::setScore(int num)
{
    score = num;
}

int Student::getScore()
{
    return score;
}

class Creator
{
public:
    static int nextID;
    Student getObject();
};
int Creator::nextID = 0;
Student Creator::getObject()
{
    Creator::nextID++;
    Student temp;
    temp.setID(Creator::nextID);
    return temp;
}

int main()
{
    Creator maker;
    Student pupil[4];

    for(std::size_t i = 0; i < (sizeof(pupil)/sizeof(pupil[0])); i++)
    {
        pupil[i] = maker.getObject();
    }

    for(std::size_t i = 0; i < (sizeof(pupil)/sizeof(pupil[0])); i++)
    {
        cout<< "Sudent ID: "<<pupil[i].getID()<<endl;
    }    

    int mark = 70;
    for(std::size_t i = 0; i < (sizeof(pupil)/sizeof(pupil[0])); i++)
    {
        pupil[i].setScore(mark);
        mark += 10;
    }

    for(std::size_t i = 0; i < (sizeof(pupil)/sizeof(pupil[0])); i++)
    {
        cout<< "Sudent ID: "<<pupil[i].getID()<<" has score of: "<<pupil[i].getScore()<<endl;
    }
    return 0;
}

该程序按预期工作,这让我感到困惑。根据我读到的内容,Student Creator::getObject()内部创建的对象不应该存在于其之外。它随着函数的返回而被破坏。然而,我正在返回Student Creator::getObject()内部创建的对象并将其存储在Student Creator::getObject()之外的pupil数组中。

既然它有效,它是否意味着对象是在堆上创建的?根据我的内容,如果在函数内部创建对象并且未使用new关键字,则会在堆栈中创建对象并在函数退出时销毁该对象。

5 个答案:

答案 0 :(得分:2)

关于这个功能:

Student Creator::getObject()
{
    Creator::nextID++;
    Student temp;
    temp.setID(Creator::nextID);
    return temp;
}

这实际上是使用类'复制构造函数创建返回值的 COPY 。确实从堆栈中删除了temp变量。

不能做什么,是这样的:

Student& Creator::getObject()
{
    Creator::nextID++;
    Student temp;
    temp.setID(Creator::nextID);
    return temp; // <- trying to return a reference transient memory
}

答案 1 :(得分:1)

  

既然它有效,它是否意味着对象是在堆上创建的?

没有。除非您致电new Student()

,否则不会自动动态分配任何内容(在堆上)
  

从我读到的内容来看,如果对象是在函数内部创建的,并且没有使用new关键字,则会在堆栈中创建对象并在函数退出时销毁该对象。

这基本上是正确的,尽管你可以返回该对象的副本作为函数的返回值,并让编译器决定return value optimization

答案 2 :(得分:0)

查看getObject的签名

Student Creator::getObject()

getObject返回您返回的任何内容的副本。确实,一旦你的函数退出,temp将被销毁,但是你没有返回对temp的引用,你将返回temp的值。

答案 3 :(得分:0)

在Java中,AFAIK在堆上创建所有对象,Java引用为您计算对象。在C ++中,如果你实例化一个对象,那么你是正确的,它是在堆栈上创建的,除非你或你调用的函数使用new。所以:

学生; //在堆栈上

学生* sp =新学生; //在堆上

学生&sr = *新生; //在堆上

在C ++中,堆栈中的所有对象在超出范围时都会被销毁,因此您的对象temp被销毁。在上面的代码中,当sp和sr本身超出范围时,sp和sr指向/引用的对象仍然存在。发生的情况是浅拷贝(默认情况下)是由temp组成的,这是返回的,然后清除temp本身。这与您返回引用的Java不同。实际上,C ++正在调用copy-constructor来制作temp的副本,并且通过为Student编写自己的copy-ctor,如果你的类有指针或参考,你就可以复制这些对象,而不仅仅是复制指针/ reference,这是默认的浅拷贝所发生的。

答案 4 :(得分:0)

temp被创建为局部变量,因此其范围确实与函数绑定。 tempgetObject结束时咬了一个大的。

但是getObject会返回Student,而不是Student的引用或指针。在这一点上,编译器的一时兴起可能会发生各种各样的酷事。可以复制temp,但由于temp永远不会再使用getObject,因此也可以移动temp。在某些情况下,可以省略// the button has to be somehow initialized and maybe added to layout QPushButton* pMyPushButton = new QPushButton(this); layout()->AddWidget(pMyPushButton); // try style it like that // the concrete example limits the scope to pMyPushButton object pMyPushButton->setStyleSheet( "QPushButton {" "background: transparent;" "image: url(res/images/normal_bn_image.png);" "}" "QPushButton:hover {" "image: url(res/images/hover_bn_image.png);" "}" ); 。编译器会做任何它认为最好的选择。

最好的部分是你可能甚至不会照顾。