该错误的意思是您试图将错误类型的值分配给变量。当错误说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>
它将管理指向int
s 分配有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) };