【问题标题】:Dynamic objects in c++ [closed]C++中的动态对象[关闭]
【发布时间】:2017-06-21 14:07:27
【问题描述】:

我从 c# 来到 c++,我不明白什么是动态对象。因此,假设您有 A 类并创建像 A *a = new A() 是 Normal 的对象,但对象 a 是什么?它和数组一样还是什么?我们可以写成 a[0] 还是 a[1]?但是如果我们重载 operator [] 并且如果我们在那里有数据并且想要正常获取数据并且想要创建动态对象会发生什么?

【问题讨论】:

  • a 是一个指针,它保存着类A 的动态分配实例的地址。一般来说,您不需要使用new 来创建新实例(并且应该避免像瘟疫一样)。
  • 对于初学者,我认为最好了解 C++ 的堆栈与堆内存分配。您可以在以下链接中找到。 learncpp.com/cpp-tutorial/79-the-stack-and-the-heap
  • 在类上重载 operator[] 与在原始指针上使用 [] 无关。如果你想调用类的 operator[] 那么你必须首先取消引用指针。
  • A *a = new A; 之间没有太大区别。和 A *a = 新 A[1];我认为的区别在于,在后一个版本中,您需要对其调用 delete [] 并且您可能只能调用该类型的默认构造函数。

标签: c++ pointers object dynamic


【解决方案1】:

指针就是它听起来的样子,它是指向其他地方的东西。

举个例子

A* a = new A;

这将变量a 声明为指针。它指向A 类的一个实例(一个对象)。

从图形上看,它可以看作是

+---+ +---------------+ |一个 | ---> | A 的实例 | +---+ +---------------+

在 C#(和 Java)中,这基本上是创建类实例的唯一方法。所有变量都是(稍微简化的)指针。

在 C++ 中,您还有其他选择:

A a;

上面的定义说变量aA类的一个实例。它不是引用,也不是指针,它一个A 对象。

现在来看看上述两个定义之间的另一个区别:在第一种情况下,A 的实例是在运行时创建的。内存是在程序运行时为实例分配的。在第二种情况下,实例的空间由编译器在编译时分配。然而,在这两种情况下,构造函数都是在运行时调用的。

【讨论】:

  • 这是一个很好的答案!我建议添加一点解决指针和数组之间的混淆。对我来说,这似乎是问题的重要组成部分。
  • 对不起,也许你不明白我的问题。我的意思是如何表示动态对象?它是一个数组吗?如果我们创建这样的对象 A *a = new A();我们可以这样写 a[1]->data = 0; 吗?
  • 它不是一个数组。这是一个单一的实例。如果它是一个数组,您希望它包含多少个元素?当您越界访问元素时,数组不会自动扩展。
  • 您对运行时分配与静态(编译器)分配的评论有点偏离。如果我在函数内声明一个变量,它会在运行时在进入该对象的范围时分配。只有当一个对象是全局(或命名空间)或各种条带的静态对象时,它才会由编译器静态分配。
【解决方案2】:

如果你写A * a = new A(),则调用A类的默认构造函数,它为A类的一个对象动态分配内存,分配的内存地址分配给指针a。所以a 指向A 类的一个对象,而不是一个数组。然而,如果你想要一个动态的A 对象数组,那么你将不得不编写类似A * a = new A[10] 的东西。这将为A 的10 个对象分配内存。你可以写a[0], a[1], ... a[9] 来访问数组的对象。

现在,如果我们重载[] 运算符会发生什么?如果我们重载[]运算符,那么它应该意味着类A内部有某种数组,通过写a[1],其中a是类A的一个对象,我们想要得到位于第二个索引的元素。 (一般来说,使用下标运算符可以表示任何其他含义,但您应该尽量坚持下标运算符的原始含义)。但是我们不能在指针上调用[] 运算符,因为这意味着取消引用指针。因此,要在对象的指针上调用下标运算符,我们必须显式调用下标运算符。像这样:

A * a = new A;
cout << a->operator[](0) << endl;

它创建A 类的一个对象,并写入a-&gt;operator[](0)。它显式调用重载的下标运算符。如果我们动态创建一个数组呢?

A * a = new A[6];
cout << a[0][0] << endl;

第一个下标运算符用于获取对象数组中的第一个对象。第二个下标运算符是调用对象a[0]的重载下标运算符

编辑:我关于调用 A 类的下标运算符是错误的。感谢 jschultz410,他纠正了我。

【讨论】:

  • “它创建一个类 A 的对象,并写入 a[0] 它给出内部数组的第一个元素,或者可能是下标运算符被重载的其他东西。”这(通常)是不正确的。写入 a[0] 会取消引用指针 a 以提供对基础类的引用。它不会在类上调用 operator[]()。你的第二个例子看起来是正确的。
  • 哦。对不起。我不知道。不过我现在学会了。谢谢。我应该从我的答案中删除它吗?虽然,如果我想调用 operator[]() 怎么办?我是否必须像这样手动调用它 -> a-&gt;operator[0]
  • 是的,但是看起来很糟糕。
  • 是的。差不多。我觉得没有别的办法了,
  • 因为它看起来很糟糕,你通常不会写a-&gt;operator[](0),而是写(*a)[0]。它仍然不漂亮,但更短且更惯用。两种语法的作用完全相同。
【解决方案3】:

'a' 是指向分配对象'A'的内存的指针(内存地址)。是的,它表现为一个数组。但是你只有一个元素,所以'a[0]'将等同于'*a'。不要在您的情况下尝试 a[1] 。它会编译,但很可能在运行时崩溃。如果您重载 [],那么现在就是您的问题了 :-)。尽管您不能在指针上重载 []。

顺便说一句,在 c# 中,'a' 也是指向对象的指针(引用),而不是对象本身。

这两种语言之间最大的区别在于,c++管理内存分配。因此,如果您说“新”,请确保在不再需要该对象时也说“删除”。

在“c+”中,您还可以创建引用而不是指针。

【讨论】:

  • 那么以及如何在指针上重载运算符 []?例如,如果您使用 uniq_ptr?
  • @icegas std::unique_ptr 是一个类,而不是一个指针。因此,您可以重载operator [] 就可以了(std::unique_ptr&lt;T[]&gt; 实际上就是这样做的)。您可能需要通读good C++ book 以更深入地掌握基本的 C++ 概念以及它们与 C# 有何不同(或不同)。
  • 指针不是对象。大多数运算符只能在对象中重载。很少有可以静态重载的,但不是'[]';如果你需要重载[],你需要在你的对象中做。在这种情况下,您可以使用引用作为比指针更方便的方式。或使用指针,但您需要这种语法才能使用它:(*pointer)[index].
猜你喜欢
  • 2013-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
  • 1970-01-01
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多