与 C++ 中的对象数组混淆

2024-04-24

所以我首先学习了Java,现在我正在尝试转向C++。我在让数组正常工作方面遇到了一些困难。

现在我只是想创建一个对象“Player”的数组并用一个对象填充它。但我收到错误。

Player* players = new Player[1];
players[0] = new Player(playerWidth, playerHeight, 20, 1);

错误说: 操作数“=”匹配这些操作数。操作数类型为: Player = Player *

我不明白为什么这不起作用?


该错误的意思是您试图将错误类型的值分配给变量。当错误说Player = Player *这意味着左侧的变量是Player右侧的值是Player *.

players[0] = new Player(playerWidth, playerHeight, 20, 1);

如果您要执行以下操作,则问题类似于:

int x;
x = "Hello, World!";

左右手类型不匹配,并且没有自然转换,因此会出现错误。


第一个问题是您有 Java 背景,而 Java 经常使用指针,但对您隐藏了它们。 C++ 根本不隐藏它们。结果是 C++ 有不同的语法来显式处理指针。 Java 摆脱了所有这些,主要使用 C++ 中的常规非指针语法来处理指针。

Java:                                  C++:

Player player = new Player();          Player *player = new Player();

Player player2;                        Player *player2 = nullptr;

** no equivalent in java **            Player player3;

player.foo();                          player->foo();

** no equivalent in java **            player3.foo();

** no equivalent in java **            *player;

** no equivalent in java **            &player2;

了解使用指针和直接使用对象之间的区别非常重要:

Java:                                  C++:

Player a = new Player();               Player *a = new Player();
Player b = a;                          Player *b = a;
b.foo();                               b->foo();

在此代码中只有一个对象,您可以通过以下任一方式访问它a or b这并没有什么区别a and b两者都是指向同一个对象的指针。

C++:

Player c = Player();
Player d = c;
d.foo();

这段代码中有两个对象。他们是独特的,并做一些事情d不影响c.

如果在 Java 中你了解了“原始”类型之间的区别,例如int和对象类型,如String那么一种思考方式是,在 C++ 中,所有对象都是原始的。如果我们回顾一下您的代码并使用“C++ 对象就像 Java 原语”规则,您也许可以更好地看到问题所在:

Java:
int[] players = new int[1];
players[0] = new int(playerWidth); // huh???

这应该清楚地表明,分配的右侧应该只是一个 Player 值,而不是新玩家对象的动态分配。对于 java 中的 int 来说,这看起来像players[0] = 100;。由于Java中的对象类型不同,Java没有办法编写对象values你可以写的方式int价值观。但 C++ 可以;players[0] = Player(playerWidth, playerHeight, 20, 1);


第二个问题是 C 中的数组很奇怪,C++ 继承了这一点。

C 和 C++ 中的指针允许“指针算术”。如果您有一个指向对象的指针,则可以对其进行添加或减去,并获得指向不同对象的指针。 Java 没有与此类似的东西。

int x[2]; // create an array of two ints, the ints are 'adjacent' to one another
// if you take the address for the first one and 'increment' it
// then you'll have a pointer to the second one.

int *i = &x[0]; // i is a pointer to the first element
int *j = &x[1]; // j is a pointer to the second element

// i + 1 equals j
// i equals j - 1

另外数组索引运算符[]适用于指针。x[5]相当于*(x+5)。这意味着指针可以用作数组,这在 C 和 C++ 中是惯用的和预期的。事实上,它甚至被融入到 C++ 中。

在 C++ 中,当你使用new动态分配对象,例如new Player,您通常会得到一个指向您指定的类型的指针。在这个例子中你得到Player *。但是当您动态分配数组时,例如new Player[5], 这不一样。而不是返回一个指向五个数组的指针Players,你实际上得到了一个指向第一个元素的指针。这就像任何其他一样Player *:

Player *p   = new Player;    // not an array
Player *arr = new Player[5]; // an array

唯一使这个指针不同的是,当你对其进行指针算术时,你会得到指向有效的指针Player对象:

Player *x = p + 1;   // not pointing at a valid Player
Player *y = arr + 3; // pointing at the fourth array element

new and delete如果在没有保护的情况下使用它们,很难正确使用。为了证明这一点:

int *x = new int;
foo();
delete x;

这段代码很容易出错,而且很可能是错误的。具体来说,如果foo()然后抛出异常x被泄露了。

在 C++ 中,每当你承担责任时,例如当你调用new您有责任致电delete稍后你应该记住

R.A.I.I.
责任* 获取即初始化

* More frequently people say 'resource acquisition is initialization', but resources are only one kind of responsibility. I was persuaded to use the latter term by Jon Kalb in one of his Exception Safe C++ http://exceptionsafecode.com/ talks.

R.A.I.I.意味着每当您获得职责时,看起来都应该像在初始化一个对象;具体来说,您正在初始化一个特殊对象,其目的是为您管理该责任。这种类型的一个例子是std::unique_ptr<int>它将管理指向ints 分配有new:

C++:

std::unique_ptr<int> x(new int);
foo();
// no 'delete x;'

管理您的Player你会使用的数组std::unqiue_ptr像这样:

std::unique_ptr<Player[]> players(new Player[1]);
players[0] = Player(playerWidth, playerHeight, 20, 1);

Now the unique_ptr将为您处理该分配,您无需致电delete你自己。 (注意,当你分配一个数组时,你应该给出unique_ptr数组类型;std::unique_ptr<Player[]>,当你分配任何其他东西时,你使用非数组类型,std::unique_ptr<Player>.)

当然,C++ 有更专业的 R.A.I.I.用于管理数组的类型,std::vector,你应该更喜欢使用它std::unique_ptr:

std::vector<Player> players(1);
players[0] = Player(playerWidth, playerHeight, 20, 1);

或者在 C++11 中:

std::vector<Player> players { Player(playerWidth, playerHeight, 20, 1) };
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

与 C++ 中的对象数组混淆 的相关文章

随机推荐

  • 单击“保存”按钮后的 WPF 数据绑定

    我有一个应用程序和一个设置窗口 其中 TabControl 包含几个 TabItems 它们每个都有一些字段 文本框 这些字段数据绑定到同一个 Singleton 对象 仅在单击 保存 按钮后 是否有任何优雅且类似 WPF 的数据绑定方式
  • iOS 7 - 呈现模式视图控制器时收到警告消息

    使用 iOS 7 编译和运行 在呈现模式视图控制器时 我收到警告消息 不鼓励在分离视图控制器上呈现视图控制器 我在使用 iOS 6 或更早版本时从未遇到过问题 任何人都可以显示在呈现模式视图控制器时是否有任何更改吗 SearchViewCo
  • 如何向打开 Chrome 控制台的用户显示警告,就像 Facebook 和 Blockchain 那样?

    当我在 Facebook 和 Blockchain 等网站上打开控制台时 我收到如下警告 我想知道如何在我的网站上执行此操作 显示警告 告诉用户这很危险 他不应该在那里粘贴任何内容 您可以设置 console log 消息的样式 conso
  • 当我尝试移动 Pygame 时,玩家回到初始位置

    当我移动玩家时 当我按住右箭头时 他会移动 10 个像素 当我释放按键时 他会返回到初始位置 顺便说一句 你不需要告诉我当我按右时他会向左移动 我知道 这是代码 import pygame pygame init WIDTH 1000 HE
  • 为什么 Java 中不能抛出和捕获对象? [复制]

    这个问题在这里已经有答案了 可能的重复 你可以在 Java 中添加什么 https stackoverflow com questions 5749898 what can you throw in java 为什么我不能在 Object
  • 如何将音频从浏览器流式传输到 WebRTC 本机 C++ 应用程序

    到目前为止 我已成功运行以下示例 WebRTC 原生 C 到浏览器视频流示例 http sourcey com webrtc native to browser video streaming example 该示例展示了如何将视频从本机
  • React Native - 如何查看 AsyncStorage 中存储的内容?

    我将一些项目保存到AsyncStorage在 React Native 中 我使用 chrome 调试器和 iOS 模拟器 不使用 React Native 使用常规 Web 开发localStorage 我能够看到存储的localStor
  • 您能解释一下流的概念吗?

    我知道流是字节序列的表示 每个流都提供了向其给定的后备存储读取和写入字节的方法 但流的意义何在 为什么我们与之交互的不是后备存储本身 不管出于什么原因 这个概念并不适合我 我读过很多文章 但我想我需要一个类比或其他东西 选择 流 这个词是因
  • Xcode 附加到进程不显示 NSLog

    我刚刚开始使用 Apple Watch 我找到了来自 五分钟观察套件 http www fiveminutewatchkit com blog category Xcode 让 iOS 应用程序和手表套件应用程序都在模拟器中运行 并且两个进
  • mongod,mac os x - rlimits警告[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我一直在我的 mac os x 10 8 上使用 mongo 昨天突然在我的日志中出现了这个警告 当启动 shell 时它也出现了 警告 软限制太低
  • 在模拟的 HttpContextBase 上设置属性

    我正在开发一个 ASP NET MVC 应用程序 并尝试针对控制器操作编写一些单元测试 其中一些操作 HttpContext 上的属性 例如 Session Request Cookies Response Cookies 等 在弄清楚如何
  • OpenTok - 如何手动发布/取消发布?

    我查看了这些链接 http www tokbox com opentok api tools js documentation overview publish html http www tokbox com opentok api to
  • 无法获取未知属性“组装”

    所以 昨天一切都很好 但现在 Android Studio 和我的项目抛出了这个错误 ERROR Could not get unknown property assemble for task patternjkh assembleDeb
  • android AlertDialog 具有透明背景

    我有一个自定义的 AlertDialog 我想使其背景完全透明 通常为了使活动完全透明 我会执行以下操作 将背景设置为 00000000在 xml 布局中 在清单集中android theme android style Theme Hol
  • 如何避免在php中刷新时重新发送数据

    我有一个页面 index php 其中有一个名为 add users php 的链接 在 add users php 中 我接受用户信息并返回到同一页面 index php 其中信息通过后操作传入并插入到数据库中 当我刷新页面或点击后退按钮
  • 如何在 Swift 中打开 URL?

    openURL已在 Swift 3 中弃用 任何人都可以提供一些如何替换的示例openURL options completionHandler 尝试打开网址时有效吗 所有你需要的是 guard let url URL string htt
  • C++ 中有标准的日期/时间类吗?

    C stl 有标准时间类吗 或者我是否必须在写入流之前转换为 c 字符串 例如 我想将当前日期 时间输出到字符串流 time t tm ostringstream sout sout lt lt tm lt lt ends 在本例中 我将当
  • 有没有好的方法来检查 Datastax Session.executeAsync() 是否引发异常?

    我试图通过调用来加速我们的代码session executeAsync 代替session execute 用于数据库写入 我们有数据库连接可能会关闭的用例 目前是之前的execute 当连接丢失 集群中没有可访问的主机 时抛出异常 我们可
  • 如何检查字符串是否是数字? [复制]

    这个问题在这里已经有答案了 我有一个 GPA 计划 它适用于equalsIgnoreCase 方法比较两个字符串 即字母 a 与用户输入 检查他们是否输入 a 但现在我想添加一个异常 其中包含当输入数字时执行的错误消息 我希望程序意识到整数
  • 与 C++ 中的对象数组混淆

    所以我首先学习了Java 现在我正在尝试转向C 我在让数组正常工作方面遇到了一些困难 现在我只是想创建一个对象 Player 的数组并用一个对象填充它 但我收到错误 Player players new Player 1 players 0