初始化程序列出了C ++和类初始化。我有no-arg构造函数但仍然需要使用初始化列表?

时间:2013-08-16 17:42:04

标签: c++ initializer-list

好的C ++新手,我非常了解Java,现在正在尝试学习c ++。 无论如何,这是我的简单课程。

class PolyGon{

    private:
        PointArray aArray;
        static int numberOfInst;

    public:
        PolyGon(Point point[], const int newSize) : aArray(point, newSize){} 
};

这符合罚款。如果我错了,请纠正我,但在初始化列表中aArray(point, newSize)等同于aArray = new PointArray(point, newSize)

因为当我尝试完全相同的代码但将最后一行更改为:

class PolyGon{

    private:
        PointArray aArray;
        static int numberOfInst;

    public:
        PolyGon(Point point[], const int newSize){aArray = new PointArray(point, newSize)} 
};

这给出了例外:

  

'(=(PolyGon *)this)中的'operator ='不匹配 - > PolyGon :: aArray =(((PointArray *)operator new(8u)),( - > PointArray :: PointArray(( (const Point *)point),newSize),))'|

如果你想在这里看到PointArray的构造函数,那就是:

PointArray::PointArray(const Point points[], const int newSize)
{
    size = newSize;

    x = new Point[size];

    for(int i = 0; i < size; i++)
    {
        x[i] = points[i];
    }
}

好的,在我提交之前,我找到了一个答案,说明如果对象没有默认构造函数,则必须使用初始化列表初始化它。我现在有三个问题:

  1. 这是为什么?为什么我不能按照我想要的方式去做。
  2. 此规则仅适用于构造函数。就像我可以说“PointArray aArray = new PointArray(point,newSize);”在其他地方?
  3. 我确实有一个no-arg构造函数。那么为什么它会给我这个错误?
  4. 我的无参数构造函数如下所示:

    PointArray(){size = 0; x = new Point[0];}
    

3 个答案:

答案 0 :(得分:3)

  

这是为什么?为什么我不能按照我想要的方式去做。

在Java中,aArray将是对您必须使用new创建的单独对象的引用。

在C ++中,您必须忘记所有关于Java对象模型的知识。 aArrayPolyGon中包含的对象,在创建PolyGon时自动创建,并在构造函数体运行之前初始化。如果需要提供构造函数参数,则必须在构造函数体之前的初始化列表中给出这些参数;当你进入构造函数体时,它已经被初始化了。

  

此规则仅适用于构造函数。我可以在其他地方说PointArray aArray = new PointArray(point, newSize);吗?

new返回指向动态对象的指针;所以你可以用它来初始化一个指针(而不是一个对象):

// Careful! This is a recipe for memory leaks.
PointArray * aArray = new PointArray(point, newSize);

但请记住,如果您使用new创建内容,则必须在完成后使用delete将其销毁。没有垃圾收集,所以放弃了动态对象泄漏内存。为防止出现这种情况,请尽可能避免使用new,并了解如何在您确实需要时使用RAII来管理动态资源。

您还可以创建没有new的对象:

PointArray aArray(point, newSize);

如果这是在代码块(局部变量;技术上,在块范围)内,那么当程序离开该块时它将被自动销毁。如果它不在任何函数内(全局变量;技术上,在命名空间范围),那么它会持续一段时间(或多或少);但全局通常被认为是一个坏主意。

  

我有一个no-arg构造函数。那么为什么它会给我这个错误呢?

正在使用默认构造函数;但是你试着给它指定一个指针。如果你真的想避开初始化列表(你不应该这样做),那么你可以通过复制临时名称来重新分配它:

PolyGon(Point point[], const int newSize) {
    aArray = PointArray(point, newSize);  // No new
} 

但这可能效率较低,并要求该类型实现它可能不需要的默认构造函数和复制赋值运算符。还有一些类型(例如常量和引用)不能默认初始化或重新分配。列表中的直接初始化适用于所有类型。

答案 1 :(得分:2)

PolyGon(Point point[], const int newSize) : aArray(point, newSize){} 

这说“作为构建PolyGon对象的第一部分,使用参数aArray构建它的内部point, newSize。我在这里故意使用”内部“这个词。为了使它更清楚,我我将使用“人”对象作为类比。在Java中,对象彼此引用。在创建一个新的人对象时,你创建一个新的(单独的)名称对象,然后告诉该人他们现在拥有这个名字。

在C ++中,它甚至不能像那样远程工作。成员(皮肤和血液)实际上是对象本身的一部分。当制作一个人物时,你必须同时制作皮肤物体和血液物体,当你制造这个人时,你不能单独制造它们然后告诉那个人他们现在拥有那个皮肤。同样,你不能在不破坏这个人的情况下将它们移除或摧毁它们。构造函数体是活着(出生)的过程。

这解释了为什么必须在构造函数体开始之前构造成员(人不能开始“生活”直到皮肤完成),以及为什么你不能给成员一个new对象(可以' t带走一个人的皮肤并给他们另一个)该成员字面该对象的一部分。初始化列表构造对象的成员,它们是字面上对象的一部分,并且对象需要“生存”。 (人类比喻在子宫里正在增长)一旦部件组装好并准备就绪,那么构造体最终开始,这开始使对象最终“活着”(出生)。

  

从C ++ 11规范,第3.8 / 1节§   类型T的对象的生命周期从...初始化完成时开始。当析构函数调用开始时,类型T的对象的生命周期结束。

所以我完全没有弥补“生命”的termononlogy。

回到C ++代码:

PolyGon(Point point[], const int newSize) 
//when making a new PolyGon
: aArray(point, newSize)
//construct it's internal aArray member at the same time
{}
//No additional steps needed to make it "live".

关于new关键字:
Java中的所有内容都需要new关键字,因为无论如何,Java都会单独存储所有对象,因此无论如何都使用new。在C ++中,我们可以在其他对象中创建对象,或者在堆栈内存中创建。我们不需要系统创建一个new对象,我们需要在我们已有的空间中构造对象。或者,如果您绝对需要单独的或动态的对象,则可以使用new在堆中创建新对象。

{
    PolyGon inst; //this construts a PolyGon object _in_ the stack space
                 //we refer to this object by the name "inst"
    inst.print_name(); //work with inst directly
    PolyGon* ptr = new PolyGon(); //this constructs a brand new PolyGon _in_ the "heap"
                                  //and a pointer _in_ the stack space
                                  //and stores the position of the PolyGon in the pointer
                                  //we refer to this _pointer_ by the name "ptr"
    ptr->print_name(); //call print_name on the object that ptr points at.
    delete ptr; //delete the thing that ptr points at
    ptr = &inst;  //now we store the address of inst in the ptr pointer object
    ptr->print_name(); //call print_name on inst
} //inst was in the stack, so as the stack unwinds, "inst" is destructed automatically
  //ptr also destructed. Destructing pointers DOES NOT destroy the things they point at

答案 2 :(得分:0)

  

aArray(point,newSize)相当于aArray = new PointArray(point,newSize)。

没有

PointArray aArray;

aArray类型为PointArray,但不是PointArray *。两者都是C ++中的不同类型。因此,当您尝试将PointArray *分配给成员变量aArray时,会出现编译错误。