C ++构造函数和如何实例化的说明

时间:2013-06-01 23:15:37

标签: c++ class gcc

我问了一个问题导致了对类实例化​​的一些混淆。

如果你有一个类A(),如:

class A
{
public:
    A();
    ~A();
};

然后我想使用该课程,可以完成以下所有操作:

// First way
A a1;
// Second way
A a1 = A();
// Third way
A::A a1 = A::A();
// Fourth way
A* a1 = new A();

我被告知第三种方式A::A a1 = A::A();不合适但似乎确实有效。

任何人都可以解释所有这些方式以及何时使用其中一种方式?我认为new在堆上而不是堆栈上分配?

示例程序:

#include <iostream>
#include <string>

class A
{
    public: 
    A();
    ~A();
};

A::A()
{
    std::cout << "A" << std::endl;
}

A::~A() {}

int main()
{   
     A a1;

    A a2 = A();

    A::A a3 = A::A();

    A* a4 = new A();

    return 0;
 }

输出:

$ ./test4
A
A
A
A

所以在g ++ 4.2中它确实有用。

$ g++ -Wall main3.cpp -o test4
main3.cpp: In function ‘int main()’:
main3.cpp:28: warning: unused variable ‘a4’

在gcc 4.8中,不是那么多:

 g++-4.8 -std=c++11 -Wall main3.cpp -o test4
main3.cpp: In function ‘int main()’:
main3.cpp:26:2: error: ‘A::A’ names the constructor, not the type
 A::A a3 = A::A();
 ^
main3.cpp:26:7: error: expected ‘;’ before ‘a3’
  A::A a3 = A::A();
       ^
main3.cpp:26:18: error: statement cannot resolve address of overloaded function
  A::A a3 = A::A();
              ^
main3.cpp:28:8: warning: unused variable ‘a4’ [-Wunused-variable]
     A* a4 = new A();
        ^

3 个答案:

答案 0 :(得分:0)

第一个使用默认构造函数初始化a1

第二个首先使用默认构造函数初始化a2,然后将由explicite调用创建的对象分配给默认构造函数。

我不认为第三种形式有效,所以我把它留下来。

最后一个分配适当大小的内存来存储类A的对象,并使用被调用的构造函数(在您的情况下为默认构造函数)初始化已分配的内存。

答案 1 :(得分:0)

您应该了解动态和静态分配之间的区别。除此之外,第一种形式是您想要使用的形式,因为它隐式调用默认构造函数。在第二种形式中,您将创建A类的临时实例并使用其自动生成的复制构造函数创建a1,但是大多数编译器只会将其优化为单个默认构造a1。第三种形式只是普通无效的C ++。第四种形式是执行动态分配,并且您没有使用delete正确释放内存,因此您在程序退出时将其留给操作系统来回收内存。

答案 2 :(得分:0)

对于你的对象,前两个版本是相同的(正式来说,第二个版本包含另一个副本,但是它被任何有价值的编译器所优化)。但是,有些对象并不相同:

如果您编写自己的默认构造函数(即使它是空的)并且的对象具有静态存储持续时间(在您的代码中,它具有自动存储持续时间),第一个版本不会初始化任何POD成员,而第二个版本将在任何情况下零初始化它们。

另一方面,如果你的类不支持复制(你明确地将复制构造函数设为私有,或者在C ++ 11中删除它并且也没有提供移动构造函数),那么第二个表单将形成不良(即使副本实际上没有发生,逻辑上它就在那里)。

你的第三种形式不是合法的C ++;如果您的编译器接受它,它可能是一个错误或非标准扩展(但我​​会打赌一个bug)。

第四种形式进行动态分配,也就是说,你有责任再次明确销毁它(使用delete a4;)。还要注意,存储在a4中的不是对象本身,而是指向它的指针;这意味着要访问该对象,您必须显式取消引用指针。

请注意,从C ++ 11开始,有一个新的初始化表单,特别适用于空参数列表,因为它结合了前两个版本的优点:它还适用于不可复制/不可移动的对象,它也初始化了POD:

A a5{};