所以我第一次学习Java,现在我正在尝试切换到C++.我让阵列正常工作有点困难.
现在我只是想创建一个对象"Player"的数组并用一个填充它.但是我收到了一个错误.
Player* players = new Player[1];
players[0] = new Player(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
错误说:操作数"="匹配这些操作数.操作数类型有:Player = Player*
我不明白为什么这不起作用?
bam*_*s53 46
错误的含义是您正在尝试为变量分配错误类型的值.当错误表示Player = Player *这意味着左侧的变量是a Player而右侧的值是a Player *.
players[0] = new Player(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
如果您这样做,问题类似于:
int x;
x = "Hello, World!";
Run Code Online (Sandbox Code Playgroud)
左手和右手类型不匹配,并且没有自然转换,因此您会收到错误.
第一个问题是你来自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;
Run Code Online (Sandbox Code Playgroud)
了解使用指针和直接使用对象之间的区别非常重要:
Java: C++:
Player a = new Player(); Player *a = new Player();
Player b = a; Player *b = a;
b.foo(); b->foo();
Run Code Online (Sandbox Code Playgroud)
在这段代码中有只有一个对象,你可以通过连接访问它a或b它不会有所作为,a并且b都指向同一个对象.
C++:
Player c = Player();
Player d = c;
d.foo();
Run Code Online (Sandbox Code Playgroud)
在此代码中有两个对象.它们是截然不同的,做一些事情d并不影响c.
如果在Java中你了解了'原始'类型int和对象类型之间的区别,String那么考虑它的一种方法是在C++中所有对象都是原始的.如果我们回顾一下您的代码并使用"C++对象就像Java原语"规则,您可以更好地看到错误:
Java:
int[] players = new int[1];
players[0] = new int(playerWidth); // huh???
Run Code Online (Sandbox Code Playgroud)
这应该清楚地表明,赋值的右侧应该只是一个Player值而不是新玩家对象的动态分配.对于java中的int,这看起来像players[0] = 100;.由于Java中的Object类型不同,Java没有办法以编写值的方式编写Object 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
Run Code Online (Sandbox Code Playgroud)
此外,数组索引运算符[]适用于指针.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
Run Code Online (Sandbox Code Playgroud)
使这个指针与众不同的唯一一点就是当你对其进行指针运算时,你会得到指向有效Player对象的指针:
Player *x = p + 1; // not pointing at a valid Player
Player *y = arr + 3; // pointing at the fourth array element
Run Code Online (Sandbox Code Playgroud)
new并且delete很难,如果你使用它们没有保护正确使用.为了证明这一点:
int *x = new int;
foo();
delete x;
Run Code Online (Sandbox Code Playgroud)
此代码容易出错,可能有误.具体来说,如果foo()抛出异常则x泄露.
在C++中,只要你有责任,比如当你打电话给new你delete时,你就有责任在以后打电话,你应该记住
RAII
责任*收购是初始化
*更频繁的人说'资源获取是初始化',但资源只是一种责任.我被说服在他的一个例外安全C++会谈中使用Jon Kalb的后一个术语.
RAII意味着无论何时您获得责任,它都应该看起来像是在初始化一个对象; 特别是你正在初始化一个特殊的对象,其目的是为你管理这个责任.这种类型的一个例子是std::unique_ptr<int>管理指向ints的指针new:
C++:
std::unique_ptr<int> x(new int);
foo();
// no 'delete x;'
Run Code Online (Sandbox Code Playgroud)
要管理您的Player阵列,您可以std::unqiue_ptr像这样使用:
std::unique_ptr<Player[]> players(new Player[1]);
players[0] = Player(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
现在,unique_ptr将为您处理该分配,您不需要delete自己打电话.(注意,当你分配一个数组时,你应该给出unique_ptr一个数组类型; std::unique_ptr<Player[]>当你分配其他任何你使用非数组类型时,std::unique_ptr<Player>.)
当然,C++有一个更专业的RAII类型来管理数组,std::vector你应该更喜欢使用std::unique_ptr:
std::vector<Player> players(1);
players[0] = Player(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
或者在C++ 11中:
std::vector<Player> players { Player(playerWidth, playerHeight, 20, 1) };
Run Code Online (Sandbox Code Playgroud)
你的类型不匹配.这也就不足为奇了,你试图把它Player*存入一个已经分配好的Player!
Player* players = new Player[1];
Run Code Online (Sandbox Code Playgroud)
这将创建一个长度为1的数组,其中包含一个实例化的数据Player,并将整个事物存储到一个数组中Player*.类型players[0]将是Player.
players[0] = new Player(...)
Run Code Online (Sandbox Code Playgroud)
这会尝试创建一个新的Player*并将其存储在数组中.但是数组包含Player对象.你应该说
players[0] = Player(...)
Run Code Online (Sandbox Code Playgroud)
或者,我猜你认为这更适合你,你应该new完全停止使用,然后使用std::vector.
std::vector<Player> players;
players.push_back(Player(playerWidth, playerHeight, 20, 1));
// or players.emplace_back(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
这不仅更容易使用,而且您也不必delete在以后记住它.当std::vector超出范围时,它将自动销毁.此外,与您的阵列不同,std::vector可以包含任意数量的对象,因此您可以随意添加新玩家或删除现有玩家.
还有其他数据结构可能更适合您,具体取决于您的确切用途,但这std::vector是一个很好的起点.
原因是,您的变量类型
players[0]
Run Code Online (Sandbox Code Playgroud)
是玩家(对象)。但是,运算符“new”(新播放器)返回一个指针(播放器*)
如果你只想拥有一个对象,正确的做法是:
Player* player = new Player(playerWidth, playerHeight, 20, 1);
Run Code Online (Sandbox Code Playgroud)
并且不要忘记在 C++ 中你需要自己清理烂摊子 - 最后调用
delete player;
Run Code Online (Sandbox Code Playgroud)
对于您创建的每个对象。C++ 没有垃圾收集器——这意味着所有手动创建的(由“新”创建的)对象会一直存在,直到您手动删除它们。