简体   繁体   English

为什么构造函数将始终具有与类相同的名称以及如何隐式调用它们?

[英]Why constructors will always have same name as of class and how they are invoked implicitly?

I want to know that why the name of constructor is always same as that of class name and how its get invoked implicitly when we create object of that class. 我想知道为什么构造函数的名称总是与类名的名称相同,以及在创建该类的对象时如何隐式调用它。 Can anyone please explain the flow of execution in such situation? 有谁能解释一下这种情况下的执行流程?

I want to know that why the name of constructor is always same as that of class name 我想知道为什么构造函数的名称总是与类名的名称相同

Because this syntax does not require any new keywords. 因为此语法不需要任何新关键字。 Aside from that, there is no good reason. 除此之外,没有充分的理由。

To minimize the number of new keywords, I didn't use an explicit syntax like this: 为了最大限度地减少新关键字的数量,我没有使用这样的显式语法:

 class X { constructor(); destructor(); } 

Instead, I chose a declaration syntax that mirrored the use of constructors. 相反,我选择了一个声明语法来反映构造函数的使用

 class X { X(); ~X(); 

This may have been overly clever. 这可能过于聪明了。 [The Design And Evolution Of C++, 3.11.2 Constructor Notation] [C ++的设计和演变,3.11.2构造函数表示法]


Can anyone please explain the flow of execution in such situation? 有谁能解释一下这种情况下的执行流程?

The lifetime of an object can be summarized like this: 对象的生命周期可以总结如下:

  1. allocate memory 分配内存
  2. call constructor 调用构造函数
  3. use object 使用对象
  4. call destructor/finalizer 调用析构函数/终结符
  5. release memory 释放记忆

In Java, step 1 always allocates from the heap. 在Java中,步骤1始终从堆中分配。 In C#, classes are allocated from the heap as well, whereas the memory for structs is already available (either on the stack in the case of non-captured local structs or within their parent object/closure). 在C#中,类也是从堆中分配的,而结构的内存已经可用(在非捕获的本地结构的情况下在堆栈中或在它们的父对象/闭包内)。 Note that knowing these details is generally not necessary or very helpful . 请注意,了解这些细节通常不是必需的或非常有用 In C++, memory allocation is extremely complicated, so I won't go into the details here. 在C ++中,内存分配非常复杂,所以我不会在这里详细介绍。

Step 5 depends on how the memory was allocated. 第5步取决于内存的分配方式。 Stack memory is automatically released as soon as the method ends. 方法结束后,堆栈存储器将自动释放。 In Java and C#, heap memory is implicitly released by the Garbage Collector at some unknown time after it is no longer needed. 在Java和C#中,垃圾收集器在不再需要它的某个未知时间内隐式释放堆内存。 In C++, heap memory is technically released by calling delete . 在C ++中,通过调用delete在技​​术上释放堆内存。 In modern C++, delete is rarely called manually. 在现代C ++中,很少手动调用delete Instead, you should use RAII objects such as std::string , std::vector<T> and std::shared_ptr<T> that take care of that themselves. 相反,您应该使用RAII对象,例如std::stringstd::vector<T>std::shared_ptr<T>来自己处理。

Why? 为什么? Because the designers of the different languages you mention decided to make them that way. 因为你提到的不同语言的设计师决定以这种方式制作它们。 It is entirely possible for someone to design an OOP language where constructors do not have to have the same name as the class (as commented, this is the case in python). 某人完全有可能设计一种OOP语言,其中构造函数不必与类具有相同的名称(如注释,python中就是这种情况)。

It is a simple way to distinguish constructors from other functions and makes the constructing of a class in code very readable, so makes sense as a language design choice. 这是区分构造函数和其他函数的简单方法,并使代码中的类构造非常易读,因此作为语言设计选择是有意义的。

The mechanism is slightly different in the different languages, but essentially this is just a method call assisted by language features (the new keyword in java and c#, for example). 这种机制在不同的语言中略有不同,但实质上这只是一种语言功能辅助的方法调用(例如java和c#中的new关键字)。

The constructor gets invoked by the runtime whenever a new object is created. 每当创建新对象时,运行时都会调用构造函数。

Seem to me that having sepearte keywords for declaring constructor(s) would be "better", as it would remove the otherwise unnecessary dependency to the name of the class itself. 在我看来,使用sepearte关键字来声明构造函数会“更好”,因为它会删除对类本身名称的其他不必要的依赖。

Then, for instance, the code inside the class could be copied as the body of another without having to make changes regarding name of the constructor(s). 然后,例如,类中的代码可以作为另一个的主体复制,而不必对构造函数的名称进行更改。 Why one would want to do this I don't know (possibly during some code refactoring process), but the point is one always strives for independency between things and here the language syntax goes against that, I think. 为什么人们想要这样做我不知道(可能在一些代码重构过程中),但重点是人们总是在努力实现事物之间的独立性,我认为语言语法与此相反。

Same for destructors. 析构函数也是如此。

One of the good reasons for constructor having the same name is their expressiveness. 构造函数具有相同名称的一个很好的理由是它们的表现力。 For example, in Java you create an object like, 例如,在Java中,您可以创建一个对象,

MyClass obj = new MyClass();  // almost same in other languages too

Now, the constructor is defined as, 现在,构造函数定义为,

class MyClass {
  public MyClass () {... }
}

So the statement above very well expresses that, you are creating an object and while this process the constructor MyClass() is called. 所以上面的语句很好地表达了,你正在创建一个对象,而在这个过程中,构造函数MyClass()被调用。

Now, whenever you create an object, it always calls its constructor. 现在,无论何时创建对象,它总是调用其构造函数。 If that class is extend ing some other Base class, then their constructor will be called first and so on. 如果该类extend了其他一些Base类,那么将首先调用它们的构造函数,依此类推。 All these operations are implicit. 所有这些操作都是隐含的。 First the memory for the object is allocated (on heap) and then the constructor is called to initialize the object. 首先分配对象的内存(在堆上)然后调用构造函数来初始化对象。 If you don't provide a constructor, compiler will generate one for your class. 如果您不提供构造函数,编译器将为您的类生成一个。

In C++, strictly speaking constructors do not have names at all. 在C ++中,严格来说构造函数根本没有名称。 12.1/1 in the standard states, "Constructors do not have names", it doesn't get much clearer than that. 在标准状态下的12.1 / 1,“构造函数没有名称”,它没有比那更清楚。

The syntax for declaring and defining constructors in C++ uses the name of the class. 在C ++中声明和定义构造函数的语法使用类的名称。 There has to be some way of doing that, and using the name of the class is concise, and easy to understand. 必须有一些方法,并使用类的名称简洁,易于理解。 C# and Java both copied C++'s syntax, presumably because it would be familiar to at least some of the audience they were targeting. C#和Java都复制了C ++的语法,大概是因为它至少对一些他们所针对的受众很熟悉。

The precise flow of execution depends what language you're talking about, but what the three you list have in common is that first some memory is assigned from somewhere (perhaps allocated dynamically, perhaps it's some specific region of stack memory or whatever). 精确的执行流程取决于你所说的语言,但你列出的三个共同之处在于,首先从某个地方分配一些内存(可能是动态分配的,也许是堆栈内存的某个特定区域或者其他)。 Then the runtime is responsible for ensuring that the correct constructor or constructors are called in the correct order, for the most-derived class and also base classes. 然后,运行时负责确保以正确的顺序调用正确的构造函数或构造函数,用于最派生的类以及基类。 It's up to the implementation how to ensure this happens, but the required effects are defined by each of those languages. 由实现决定如何确保这种情况发生,但所需的效果由每种语言定义。

For the simplest possible case in C++, of a class that has no base classes, the compiler simply emits a call to the constructor specified by the code that creates the object, ie the constructor that matches any arguments supplied. 对于C ++中最简单的情况,对于没有基类的类,编译器只是调用由创建对象的代码指定的构造函数,即与提供的任何参数匹配的构造函数。 It gets more complicated once you have a few virtual bases in play. 一旦你有几个虚拟基地,它会变得更加复杂。

I want to know that why the name of constructor is always same as that of class name 我想知道为什么构造函数的名称总是与类名的名称相同

So that it can be unambigously identified as the constructor. 这样它就可以毫不含糊地被识别为构造函数。

and how its get invoked implicitly when we create object of that class. 以及当我们创建该类的对象时如何隐式调用它。

It is invoked by the compiler because it has already been unambiguously identified because of its naming sheme. 它由编译器调用,因为它已经被明确地识别,因为它的命名符号。

Can anyone please explain the flow of execution in such situation? 有谁能解释一下这种情况下的执行流程?

  1. The new X() operator is called. 调用新的X()运算符。
  2. Memory is allocated, or an exception is thrown. 分配内存,或抛出异常。
  3. The constructor is called. 调用构造函数。
  4. The new() operator returns to the caller. new()运算符返回给调用者。

the question is why designers decided so? 问题是为什么设计师决定如此?

Naming the constructor after its class is a long-established convention dating back at least to the early days of C++ in the early 1980s, possibly to its Simula predecessor. 在类之后命名构造函数是一个历史悠久的约定,至少可以追溯到20世纪80年代早期的C ++早期,可能是它的Simula前身。

The convention for the same name of the constructor as that of the class is for programming ease, constructor chaining, and consistency in the language. 构造函数与该类的名称相同的约定用于编程简易性,构造函数链接以及语言的一致性。

For example, consider a scenario where you want to use Scanner class, now what if the JAVA developers named the constructor as xyz! 例如,考虑一个您想要使用Scanner类的场景,现在如果JAVA开发人员将构造函数命名为xyz,该怎么办!

Then how will you get to know that you need to write : 那你怎么知道你需要写:

Scanner scObj = new xyz(System.in) ; 扫描仪scObj = new xyz(System.in);

which could've have been really weird, right! 这可能真的很奇怪,对! Or, rather you might have to reference a huge manual to check constructor name of each class so as to get object created, which is again meaningless if you could have a solution of the problem by just naming constructors same as that of the class. 或者,您可能必须引用一个巨大的手册来检查每个类的构造函数名称以便创建对象,如果您只需命名构造函数与类的构造函数相同就可以解决问题,那么这也是毫无意义的。

Secondly, the constructor is itself created by the compiler if you don't explicitly provide it, then what could be the best name for constructor could automatically be chosen by the compiler so it is clear to the programmer! 其次,构造函数本身是由编译器创建的,如果你没有显式提供它,那么构造函数的最佳名称可以由编译器自动选择,所以程序员很清楚! Obviously, the best choice is to keep it the same as that of the class. 显然,最好的选择是保持与班级相同。

Thirdly, you may have heard of constructor chaining, then while chaining the calls among the constructors, how the compiler will know what name you have given to the constructor of the chained class! 第三,您可能听说过构造函数链接,然后在构造函数中链接调用时,编译器将如何知道您为链接类的构造函数指定了什么名称! Obviously, the solution to the problem is again same, KEEP NAME OF THE CONSTRUCTOR SAME AS THAT OF THE CLASS. 显然,问题的解决方案也是一样的,保持构造者的名称与类的一样。


When you create the object, you invoke the constructor by calling it in your code with the use of new keyword(and passing arguments if needed) then all superclass constructors are invoked by chaining the calls which finally gives the object. 在创建对象时,通过使用new关键字在代码中调用它来调用构造函数(并在需要时传递参数),然后通过链接最终给出对象的调用来调用所有超类构造函数。

Thanks for Asking. 谢谢你的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM