创建一个对象:A.new或new A?

时间:2009-10-17 09:26:32

标签: c++ language-design instance

出于好奇:为什么C ++选择a = new A而不是a = A.new作为实例化对象的方式?后者是不是更像是面向对象?

8 个答案:

答案 0 :(得分:12)

  

出于好奇:为什么C ++选择a = new A而不是a = A.new作为实例化对象的方式?后者是不是更像是面向对象?

是吗? 这取决于你如何定义“面向对象”。

如果你定义它,就像Java所做的那样,“一切都必须具有”X.Y“的语法,其中X是一个对象,Y是你想要的任何东西与那个对象有关,那么是的,你是对的。这不是面向对象的,Java是OOP编程的顶峰。

但幸运的是,也有一些人认为“面向对象”应该与对象的行为相关,而不是在它们上使用哪种语法。基本上应该归结为Wikipedia页面所说的内容:

  

面向对象编程是一种编程范例,它使用“对象” - 由数据域和方法及其交互组成的数据结构 - 来设计应用程序和计算机程序。编程技术可能包括信息隐藏,数据抽象,封装,模块化,多态和继承等功能

请注意,它没有说明语法。它没有说“你必须通过指定一个对象名称后跟一个点后跟函数名称来调用每个函数”。

根据该定义,foo(x)与面向对象完全一样x.foo()。 重要的是x是一个对象,也就是说,它由数据域和一组方法组成,通过这些方法可以对其进行操作。在这种情况下,foo显然是其中一种方法,无论它在何处定义,并且无论在调用它时使用哪种语法。

C ++大师很久以前就意识到了这一点,并撰写了诸如this之类的文章。 对象的接口只是成员方法的集合(可以使用点语法调用)。它是可以操纵对象的一组函数。无论他们是会员还是朋友,都无所谓。它是面向对象的,只要对象能够保持一致,也就是说,它能够阻止任意函数搞乱它。

那么,为什么A.new会更加面向对象?这种形式如何为你提供“更好”的对象?

OOP背后的关键目标之一是允许更多可重用的代码。

如果new是每个班级的成员,那就意味着每个班级都必须定义自己的 new操作。而当它是非成员时,每个类都可以重用相同的成员。由于功能是相同的(分配内存,调用构造函数),为什么不把它放在所有类可以重用它的开放中? (先发制人的挑剔:当然,同样的new实现也可以在这种情况下重用,通过继承一些常见的基类,或者只是通过一些编译魔术。但最终,为什么呢,当我们可以把机制放在课外“

答案 1 :(得分:11)

C ++中的.仅用于成员访问,因此点的右侧始终是对象而不是类型。如果有的话,A::new()A.new()更符合逻辑。

在任何情况下,动态对象分配都是特殊的,因为编译器分配内存并分两步构造一个对象,并添加代码来处理异常,确保永远不会泄漏内存。使其看起来像成员函数调用而不是特殊操作可以被视为模糊操作的特殊性质。

答案 2 :(得分:3)

我认为这里最大的困惑是 new 有两个含义:内置的new-expression(它结合了内存分配和对象创建)然后是可重载的operator new(这是一个特权)只有内存分配)。据我所知,第一个是你无法改变的行为,因此把它伪装成一个成员函数是没有意义的。 (或者它必须是 - 或者看起来像 - 一个没有类可以实现/覆盖的成员函数!!)

这也会导致另一个不一致:

 int* p = int.new;

C ++不是纯粹的OOP语言,因为并非所有东西都是对象。

C ++还允许使用自由函数(这是一些作者和SC ++ L设计中的示例所鼓励的),这是C ++程序员应该习惯的。当然,new-expression不是一个函数,但是我没有看到语法提醒隐含的自由函数调用如何能让任何人放弃一个自由函数调用很常见的语言。

答案 3 :(得分:2)

请阅读代码(它有效),然后你会有不同的想法:

CObject *p = (CObject*)malloc(sizeof *p);
...
p = new(p) CObject;
p->DoSomthing();
...

答案 4 :(得分:1)

A.newA的静态函数,而a = new A分配内存并随后调用对象的构造函数

答案 5 :(得分:1)

实际上,如果添加正确的方法,可以使用A.new之类的实例化对象:

class A{
  public: static A* instance()
  {  return new A(); }
};

A *a = A::instance();

但事实并非如此。语法也不是这样的:你可以通过检查它的右侧来区分::.“操作”。

我认为原因是内存管理。在C ++中,与许多其他面向对象语言不同,内存管理由用户完成。虽然标准库和非标准库包含它,但没有默认的垃圾收集器,还有各种管理内存的技术。因此,程序员必须查看 new运算符才能理解内存分配是否涉及

除非已经过载,否则首先使用new运算符分配原始内存,然后调用在分配的内存中构建它的对象构造函数。由于这里涉及“原始”低级操作,它应该是一个单独的语言操作符,而不仅仅是类方法之一。

答案 6 :(得分:0)

我认为没有理由。它是a = new a只是因为它首先以这种方式起草。事后看来,它应该是a = a.new();

答案 7 :(得分:0)

为什么每个班级都应该有新的分开?

我认为根本不需要它,因为新的目标是 分配适当的内存并通过调用构造函数构造对象。 因此,无论任何阶级,新的行为都是独特和独立的。那么为什么不做可以恢复?

当您想要自己进行内存管理时(例如,通过分配内存池并按需返回内存),您可以覆盖new。