C++ C++;构造函数以及如何实例化的说明

C++ C++;构造函数以及如何实例化的说明,c++,class,gcc,C++,Class,Gcc,我问了一个导致类实例化混乱的问题 如果您有一个类a(),如: 然后我想与该类合作,可以完成以下所有操作: // First way A a1; // Second way A a1 = A(); // Third way A::A a1 = A::A(); // Fourth way A* a1 = new A(); 我被告知第三条路A::a1=A::A()不合适,但似乎确实有效 有谁能解释一下所有这些方法,以及什么时候使用它们?我认为new是在堆上而不是堆栈上分配的 示例程序: #inclu

我问了一个导致类实例化混乱的问题

如果您有一个类a(),如:

然后我想与该类合作,可以完成以下所有操作:

// First way
A a1;
// Second way
A a1 = A();
// Third way
A::A a1 = A::A();
// Fourth way
A* a1 = new 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;
 }
因此,在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();
        ^

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

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


我认为第三种形式行不通,所以我把它删掉了


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

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

对于您的对象,前两个版本是相同的(从形式上讲,第二个包含另一个副本,但这是由任何值得使用的编译器优化的)。但是,有些对象并不完全相同:

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

另一方面,如果您的类不支持复制(您显式地将复制构造函数设置为私有,或者在C++11中删除了它,并且没有提供移动构造函数),那么第二种形式将是格式错误的(即使复制实际上没有发生,逻辑上它也存在)

你的第三表单不是合法的C++;如果你的编译器接受它,它是bug或者非标准扩展(我会赌上一个bug)。 第四种形式是动态分配的,也就是说,您有责任再次显式销毁它(使用

delete a4;
)。还要注意,a4中存储的不是对象本身,而是指向它的指针;这意味着要访问对象,您必须显式取消引用指针

请注意,自C++11以来,出现了一种新的初始化形式,尤其适用于空参数列表,因为它结合了前两个版本的优点:它也适用于不可复制/不可移动的对象,并且它还初始化了POD:

A a5{};

这里的问题是错误的,因为我们只能花几分钟来回答你的问题。最好花几个小时来研究一本好的C++编程书籍。C++是一种很难学的语言,你需要很多时间。并学习使用调试器(
gdb
在Linux上)。我认为第三种形式不起作用()“安迪,谢谢你。我促使我尝试G++ 4.2和4.8,参见上面的更新。@杰森,请从你的例子中取出它,请不要使用它。Visual C++让你做这些是出于古老的原因,忽略了A::在La.A3被接受到GCC 4.4,标记为4.5的错误——它们修复了bug。A: A是A类的构造函数,而不是一种类型,所以必须被拒绝。实际上,如果代码<>代码>一个有效的命名空间,第三形式是合法的。@ GeavyWror:它不在给定的示例程序中。我想我会提到它,因为它可能误导OP,认为这不是合法的C++语法。
 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();
        ^
A a5{};