Объявление нескольких указателей объектов в одной строке вызывает ошибку компилятора
когда я это делаю (в своем классе)
public:
Entity()
{
re_sprite_eyes = new sf::Sprite();
re_sprite_hair = new sf::Sprite();
re_sprite_body = new sf::Sprite();
}
private:
sf::Sprite* re_sprite_hair;
sf::Sprite* re_sprite_body;
sf::Sprite* re_sprite_eyes;
Все работает отлично. Однако, если я изменю объявления на это:
private:
sf::Sprite* re_sprite_hair, re_sprite_body, re_sprite_eyes;
Я получаю эту ошибку компилятора:
error: no match for 'operator=' in '((Entity*)this)->Entity::re_sprite_eyes = (operator new(272u), (<statement>, ((sf::Sprite*)<anonymous>)))
И затем он говорит, что кандидаты на re_sprite_eyes
являются sf::Sprite
объектами и/или ссылками.
Почему это не работает? Разве объявления не совпадают?
Ответы
Ответ 1
sf::Sprite* re_sprite_hair, re_sprite_body, re_sprite_eyes;
Не объявляет 3 указателя - это один указатель и 2 объекта.
sf::Sprite*
, к сожалению, не относится ко всем объявленным после него переменным, только первым. Это эквивалентно
sf::Sprite* re_sprite_hair;
sf::Sprite re_sprite_body;
sf::Sprite re_sprite_eyes;
Вы хотите сделать:
sf::Sprite *re_sprite_hair, *re_sprite_body, *re_sprite_eyes;
Вам нужно поместить одну звезду для каждой переменной. В таких случаях я предпочитаю держать звезду на переменной стороне, а не на типе, чтобы сделать эту ситуацию ясной.
Ответ 2
В C и С++ *
привязывается к объявлению, а не к спецификатору типа. В обоих языках декларации основаны на типах выражений, а не на объектах.
Например, предположим, что у вас есть указатель на int
с именем p
, и вы хотите получить доступ к значению int
, на которое указывает p
; вы делаете это путем разыменования указателя унарным оператором *
, например:
x = *p;
Тип выражения *p
равен int
; Таким образом, декларация p
есть
int *p;
Это верно, независимо от того, сколько указателей вы заявляете в одном заявлении декларации; если q
и r
также должны быть объявлены как указатели, то они также должны иметь унарный *
как часть декларатора:
int *p, *q, *r;
потому что выражения *q
и *r
имеют тип int
. Это случайность синтаксиса C и С++, которую вы можете написать T *p
, T* p
или T * p
; все эти декларации будут интерпретироваться как T (*p)
.
Вот почему я не люблю стиль С++ для объявления указателей и ссылочных типов как
T* p;
T& r;
потому что это подразумевает неправильное представление о синтаксисе объявления C и С++, что приводит к точному виду замешательства, которое вы только что испытали. Однако я написал достаточно С++, чтобы понять, что бывают случаи, когда этот стиль делает код более понятным, особенно при определении типов контейнеров.
Но это все еще неправильно.
Ответ 3
В С++ 11 у вас есть небольшое небольшое обходное решение, которое может быть лучше, чем перемещение пробелов вперед и назад:
template<typename T> using type=T;
template<typename T> using func=T*;
// I don't like this style, but type<int*> i, j; works ok
type<int*> i = new int{3},
j = new int{4};
// But this one, imho, is much more readable than int(*f)(int, int) = ...
func<int(int, int)> f = [](int x, int y){return x + y;},
g = [](int x, int y){return x - y;};
Ответ 4
Еще одна вещь, которая может привлечь ваше внимание, - это строка:
int * p1, * p2;
Это объявляет два указателя, используемые в предыдущем примере. Но обратите внимание, что для каждого указателя есть звездочка (*
), чтобы у обоих был тип int*
(указатель на int). Это необходимо из-за правил приоритета. Обратите внимание, что если вместо этого код был:
int * p1, p2;
p1
действительно будет иметь тип int*
, но p2
будет иметь тип int
. Пространства для этой цели не имеют значения. Но в любом случае просто помнить о том, чтобы поставить одну звездочку на указатель, достаточно для большинства пользователей-указателей, заинтересованных в объявлении нескольких указателей на оператор. Или еще лучше: используйте разные statemet для каждой переменной.
Из http://www.cplusplus.com/doc/tutorial/pointers/
Ответ 5
Звездочка привязывается к имени переменной-указателя. Способ запомнить это - заметить, что в C/С++ объявления мимируют использование.
Указатели могут использоваться следующим образом:
sf::Sprite *re_sprite_body;
// ...
sf::Sprite sprite_bod = *re_sprite_body;
Аналогично,
char *foo[3];
// ...
char fooch = *foo[1];
В обоих случаях существует базовый тип-спецификатор, а оператор или операторы должны "получить" объект этого типа в выражении.