为什么在创建具有关联指针的对象时使用'new'?

时间:2014-02-06 23:50:26

标签: c++ object pointers heap

我正在通过阅读教科书来学习C ++。 “对象和指针”部分说,声明指向这样的对象的指针:

SomeClass *ptrMyClass;

本身没有任何作用。只有在定义了Class的实例之后才有意义,如下所示:

SomeClass *ptrMyClass;
ptrMyClass = new SomeClass;

或者将它们组合在一起:

SomeClass *ptrMyClass = new SomeClass;

我的问题是,为什么我们必须使用'new'在堆上创建SomeClass的实例?到目前为止,在本书中,指针始终指向“正常”变量(如int,float ...),这些变量不是通过使用“new”创建的。谢谢。

4 个答案:

答案 0 :(得分:4)

在C ++中实例化对象有两种主要方式:堆栈和堆(或免费存储)。例如:

void func()
{
    // On the stack:
    Widget blah;

    // On the heap:
    Widget * foo = new Widget;
    delete foo;
}

堆栈对象/变量的优点是它们分配/访问的速度往往更快,而且它们更容易使用。但是,堆栈的大小有限,数据通常仅限于本地范围(全局变量除外,通常是不可取的)。也就是说,只要blah结束,上面示例中的func()对象就会自动销毁。你无能为力。因此,当原始项目超出范围时,任何指向堆栈对象/变量的指针都将变为无效(即“悬空”)。

堆(通常)更大,因此它可以处理比堆栈更多的数据。它往往稍微慢一点,但它的优点是让你在运行时重新分配东西。相比之下,堆栈对象/变量(尤其是数组)在编译时是固定的。

此外,在堆上分配了一个对象后,只要需要它就可以将它保留在那里,并保持对它的有效指针。在过去,您必须最终调用delete以避免内存泄漏。在现代C ++中,鼓励使用智能指针(例如std::shared_ptr)。

作为补充说明,在声明类成员时会稍微复杂一些。如果对象在堆栈上实例化,那么它的任何直接成员(即组合成员)也将在堆栈上。如果对象在堆上实例化,那么它的所有成员都将在堆上。

答案 1 :(得分:2)

  

我的问题是,为什么我们必须使用'new'在堆上创建SomeClass的实例?

你没有。您可以使用new动态创建对象。或者,您可以获得指向现有对象的指针

SomeClass* ptrMyClass1;     // An uninitialized pointer.

                            // If an automatic object its value is indeterminate and
                            // You have not defined what it points at. It should not
                            // be used (until you explicitly set it to something).

                            // If a static object then it is initialized to NULL
                            // i.e. Global (or other static storage duration object).

SomeClass* ptrMyClass2 = new SomeClass; // A pointer to a dynamically 
                                        // allocated object.

SomeClass  objMyClass3;                 // A normal object
SomeClass* ptrMyClass4 = &objMyClass3;  // A pointer to a normal object

答案 2 :(得分:2)

为什么要在堆中创建类的实例

有一种情况,你必须做这种事情。

当你使用没有具体方法的抽象类,以及从该抽象类继承的类时(在Java或PHP世界中,我们将讨论从interface继承):

class IMyAbstractClass
{
public:
    virtual int myFunction(void) = 0;
};

class MyInheritedClass : public IMyAbstractClass
{
public:
    int myFunction(void)
    {
        // doSomething
        return 0;
    }
};

如果需要通过它们继承的抽象类来引用继承类的实例,那么语法是:

IMyAbstractClass * myInstance;
myInstance = new MyInheritedClass;

那么它允许你做什么?

以这种方式声明对象之后,您可以将它作为IMyAbstractClass的实例传递给另一个对象的构造函数:

AnotherClass anotherObject(myInstance);

这个构造函数的编码如下:

class AnotherClass
{
public:
    AnotherClass(IMyAbstractClass * instance)
    {
        // doSomething
    }
};

现实生活中的任何地方?

Strategy design pattern中使用了这种行为。

答案 3 :(得分:1)

  

为什么我们必须使用'new'在堆上创建SomeClass的实例?

你不必须。您还可以引用在堆栈上创建的实例:

SomeClass some;
SomeClass* ptrMyClass(&some);