c++ - C++中初始化对象的不同方式

标签 c++ class c++11 constructor initialization

想象一下这个类:

class Entity {
public:
    int x, y;
    
    Entity() : x(0), y(0) { }
    Entity(int x, int y) : x(x), y(y) { }
}

这里有多种我认为我知道的初始化类的方法:

Entity ent1;                //Uses the default constructor, so x=0 and y=0
Entity ent2();              //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2);          //Made constructor, so x=1 and y=2
Entity ent4 = Entity();     //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3

我知道可以在堆内存上创建一个对象,但这不是我现在要找的。

我的问题是,这些初始化对象的方式有什么区别?

我不确定什么时候应该使用哪一个。

最佳答案

初始化的区别不仅在于它采用的形式,还在于 在正在初始化的实体类型中。在这种情况下,它是一个类类型的对象,具有已定义的默认构造函数以及带参数的构造函数。

Entity ent1;  

上面的语句是默认初始化,它会调用 Entity 类的默认构造函数。


Entity ent2();

如果可能的话,上面的声明将被编译器视为函数原型(prototype)。 Entity 将返回函数 ent2 的类型,它不带任何参数。它被称为最令人烦恼的解析 (MVP) 的案例,它的存在导致出现误导性的“聪明的愚蠢规则”:“永远不要使用括号”。


在这样的语句中,为 ent3 对象调用匹配参数列表的用户定义构造函数:

Entity ent3(1, 2);    // calls Entity(int x, int y)

另一种 MVP 可以罢工的情况是这样的:

Entity ent3_1(int(a), int(b));  // It's not what it looks like.
上面的

ent3_1 不是变量。该语句声明了一个带有两个 int 参数的函数。 int(a)int a 相同是 C 语言和声明语法的遗留问题,忽略了“额外”括号。


Entity ent4 = Entity();
在 C++11 之前,

ent4ent2正确 版本。默认构造函数作为值初始化的一部分被调用。它的形式允许避免使 ent2ent3_1 不正确的歧义解决原则。这里的等号不是赋值,因为这里不会发生 operator= 调用。它是声明语法的一部分,用于标记初始化表达式。


Entity ent5 = Entity(2, 3);

ent5 是 ent3 大小写的一个版本。作为值初始化的一部分调用的用户定义的构造函数。


你的问题被标记为 C++11,C++11 允许统一的初始化语法:

Entity ent12{};     // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {};              // Not an assignment
Entity ent15 = Entity{2, 3};    // Not an assignment either!

请注意,统一初始化语法有一个警告。例如。这条线

std::vector<int> v(10); 

声明一个包含 10 个元素的 vector 。但是这个

std::vector<int> v{10};

声明一个用值为 10 的 int 类型的单个元素初始化的 vector 。发生这种情况是因为 std::vector 具有定义了以下签名的构造函数:

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

如果您既不能在不触发 MVP 的情况下使用 (),也不能在不调用不需要的构造函数的情况下使用 {},则值初始化赋值语法可以解决该问题。

附录:必看CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”

关于c++ - C++中初始化对象的不同方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49802012/

相关文章:

C++11 如何观察 atomic::store 和 atomic::load 中的内存顺序

java - 如何替换java中的System类?

c# - 在接口(interface)中使用基类

c++ - g++ 编译器为表达式提供 << 类型错误,但在 Visual Studio 中有效

c++ - 在将 unique_ptr 移动到同一对象的基类构造后,使用指向对象的原始指针初始化字段

Python:彼此为 "talk"的类

c++ - 模板常量/非常量方法

c++ - cpp 中结构的未解析外部符号?

Android native 库 - 写入日志的序列化方式

c++ - 保护程序中的 C++ 代码