我想知道为什么构造函数的名称总是与类名的名称相同,以及在创建该类的对象时如何隐式调用它。有谁能解释一下这种情况下的执行流程?
答案 0 :(得分:13)
我想知道为什么构造函数的名称总是与类名
的名称相同
因为此语法不需要任何新关键字。除此之外,没有充分的理由。
为了尽量减少新关键字的数量,我没有使用这样的显式语法:
class X { constructor(); destructor(); }
相反,我选择了一个声明语法,它反映了构造函数的 use 。
class X { X(); ~X();
这可能过于聪明了。 [C ++的设计和演变,3.11.2构造函数表示法]
有谁可以解释这种情况下的执行流程?
对象的生命周期可以这样总结:
在Java中,步骤1始终从堆中分配。在C#中,类也是从堆中分配的,而结构的内存已经可用(在非捕获的本地结构的情况下在堆栈中或在它们的父对象/闭包内)。 Note that knowing these details is generally not necessary or very helpful。在C ++中,内存分配非常复杂,所以我不会在这里详细介绍。
步骤5取决于内存的分配方式。方法结束后,堆栈存储器将自动释放。在Java和C#中,垃圾收集器在不再需要它的某个未知时间内隐式释放堆内存。在C ++中,通过调用delete
在技术上释放堆内存。在现代C ++中,delete
很少被手动调用。相反,您应该使用自己处理的std::string
,std::vector<T>
和std::shared_ptr<T>
等RAII对象。
答案 1 :(得分:6)
为什么呢?因为你提到的不同语言的设计师决定以这种方式制作它们。某人完全有可能设计一种OOP语言,其中构造函数不必与类具有相同的名称(如注释,python中就是这种情况)。
这是一种区分构造函数与其他函数的简单方法,并使代码中的类构造非常易读,因此作为语言设计选择是有意义的。
这种机制在不同语言中略有不同,但实质上这只是一种语言功能辅助的方法调用(例如java和c#中的new
关键字)。
每当创建新对象时,运行时都会调用构造函数。
答案 2 :(得分:4)
对我来说,使用sepearte关键字来声明构造函数会“更好”,因为它会删除对类本身名称的其他不必要的依赖。
然后,例如,类中的代码可以作为另一个的主体复制,而不必对构造函数的名称进行更改。为什么人们想要这样做我不知道(可能在一些代码重构过程中),但重点是人们总是在努力实现事物之间的独立性,我认为语言语法与此相反。
相同的析构函数。
答案 3 :(得分:2)
构造函数具有相同名称的一个很好的理由是它们的表现力。例如,在Java中,您可以创建一个对象,如
MyClass obj = new MyClass(); // almost same in other languages too
现在,构造函数定义为
class MyClass {
public MyClass () {... }
}
所以上面的语句很好地表达了,你正在创建一个对象,而在这个过程中,构造函数MyClass()
被调用。
现在,无论何时创建对象,它总是调用其构造函数。如果该类是extend
其他一些Base类,那么将首先调用它们的构造函数,依此类推。所有这些操作都是隐含的。首先分配对象的内存(在堆上)然后调用构造函数来初始化对象。如果您不提供构造函数,编译器将为您的类生成一个。
答案 4 :(得分:2)
在C ++中,严格来说构造函数根本没有名称。 12.1 / 1在标准状态下,“构造函数没有名称”,它没有比那更清楚。
在C ++中声明和定义构造函数的语法使用类的名称。必须有一些方法,并使用类的名称简洁,易于理解。 C#和Java都复制了C ++的语法,大概是因为它至少对他们所针对的一些观众来说是熟悉的。
精确的执行流程取决于你所说的语言,但你列出的三个共同之处在于,首先从某个地方分配一些内存(可能是动态分配的,也许是堆栈内存的某些特定区域或者其他)。然后,运行时负责确保以正确的顺序调用正确的构造函数或构造函数,用于最派生的类以及基类。由实现决定如何确保这种情况发生,但所需的效果由每种语言定义。
对于C ++中最简单的情况,对于没有基类的类,编译器只是调用由创建对象的代码指定的构造函数,即与提供的任何参数匹配的构造函数。一旦你有几个虚拟基地,它会变得更加复杂。
答案 5 :(得分:1)
我想知道为什么构造函数的名称总是与之相同 班级名称
因此可以毫不含糊地将其识别为构造函数。
以及在创建该类的对象时如何隐式调用它。
它由编译器调用,因为它已经被明确地识别,因为它的命名符号。
有谁可以解释这种情况下的执行流程?
问题是为什么设计师决定这样做?
在类之后命名构造函数是一个历史悠久的约定,至少可以追溯到20世纪80年代早期的C ++早期,可能是它的Simula前身。
答案 6 :(得分:0)
构造函数与类相同的名称的约定是为了简化编程,构造函数链接和语言的一致性。
例如,考虑一个要使用Scanner类的场景,现在,如果JAVA开发人员将构造函数命名为xyz会怎样!
然后您将如何知道需要写:
Scanner scObj = new xyz(System.in);
这本来是很奇怪的,对!或者,更确切地说,您可能必须参考大量手册来检查每个类的构造函数名称以创建对象,如果仅通过命名与该类相同的构造函数就可以解决问题,那么这又毫无意义。 / p>
第二,如果您未明确提供构造函数,则构造函数本身是由编译器创建的,那么编译器会自动选择最适合构造函数的名称,因此程序员很清楚!显然,最好的选择是与班级保持一致。
第三,您可能听说过构造函数链接,然后在构造函数之间链接调用时,编译器将如何知道您给链接类的构造函数指定了什么名称!显然,解决该问题的方法还是相同的,将构造函数的名称保留为该类的名称。
创建对象时,您可以通过使用new关键字(并在需要时传递参数)在代码中对其进行调用来调用构造函数,然后通过链接最终提供该对象的调用来调用所有超类构造函数。
感谢提问。