现在我只是试图创建一个对象“Player”的数组,并用一个填充它.但是我收到一个错误.
Player* players = new Player[1]; players[0] = new Player(playerWidth,playerHeight,20,1);
错误说:
操作数“=”匹配这些操作数.操作数类型为:Player = Player *
我不明白为什么这不工作?
解决方法
players[0] = new Player(playerWidth,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或b访问它,并没有什么区别,a和b都是同一个对象的指针.
C++: Player c = Player(); Player d = c; d.foo();
在这段代码中有两个对象.他们是独特的,做某事不影响c.
如果在Java中,您了解到像“String”这样的“primitive”类型之间的区别,那么一个想法就是在C中所有对象都是原始的.如果我们回顾你的代码,并使用这个’C对象就像Java原语’规则,你可能会看到更好的是什么问题:
Java: int[] players = new int[1]; players[0] = new int(playerWidth); // huh???
这应该清楚,任务的右侧应该只是一个Player值,而不是一个新的玩家对象的动态分配.对于java中的int来说,这看起来像玩家[0] = 100;由于Java中的对象类型不同Java没有办法通过写入int值的方式写入Object值.但是C呢player [0] = Player(playerWidth,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中,当您使用新的动态分配对象,例如新玩家,你通常会得到一个指向你指定的类型的指针.在此示例中,您将获得Player *.但是当您动态分配数组时,例如新玩家[5],这是不同的.而不是返回一个指向五个玩家数组的指针,您实际上会获得一个指向第一个元素的指针.这就像任何其他玩家*:
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
如果您在没有保护的情况下使用它们,则新建和删除将很难正确使用为了证明这一点:
int *x = new int; foo(); delete x;
此代码容易出错,可能是错误的.具体来说,如果foo()抛出一个异常,那么x被泄漏.
在C任何时候,如果你收到一个责任,比如当你打电话给你时,你会收到以后调用delete的责任,你应该记住
R.A.I.I.
Responsibility* Acquisition Is Initialization
更多的人说“资源获取是初始化”,但资源只是一种责任.在他的Exception Safe C++次谈判中,我被劝说使用后者Jon Kalb.
R.A.I.I.意味着每当你获得责任时,它应该看起来像你正在初始化一个对象;具体来说,您正在初始化一个特殊对象,其目的是为您管理该责任.这种类型的一个例子是std :: unique_ptr< int>它将管理分配给new的int指针:
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,1);
现在,unique_ptr将为您处理该分配,您不需要自己调用delete. (N.B.当你分配一个数组时,你应该给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,1);
或者在C 11:
std::vector<Player> players { Player(playerWidth,1) };