#c #class #friend
#c #класс #друг
Вопрос:
Я просто возвращаюсь к C с моим другом. Я пишу базовую текстовую игру dungeon, пытаясь заставить игрока двигаться вверх, вниз, влево и вправо. Ну, мой вопрос состоит из двух частей.
Я создал класс Map, класс Player и класс GameLoop. Все, что происходит, очевидно, происходит внутри моего игрового цикла. Класс Map имеет функцию Move () для перемещения игрока. В классе Map должен ли я разрешить моему классу Player иметь дружеский доступ к классу Map? Я немного запутался, когда использовать классы friend. Мне интересно, должна ли функция игрового цикла использовать map.Move(), или я должен поместить Move () в класс Player, подружить их и использовать player.Переместить().
Мой класс Map содержит личные данные координат, в которых расположен мой проигрыватель.
Я знаю, это может быть немного субъективно, но я как бы говорю в целом. Является ли использование класса friend более эффективным, чем прямое использование объекта Map?
Перейдем ко второму вопросу. Я знаю, что классы очень распространены, но мне интересно, являются ли объекты. Должен ли быть создан хотя бы один объект для каждого класса, или вы могли бы даже создать класс и использовать его, не создавая объект?
Комментарии:
1. Почему вы решили создать
Move()
функцию-член изMap
, а неPlayer
?2. @Maxpm: для этого есть много причин, одна из которых заключается в том, что
Map
инкапсулирует местоположение игрока. Это действительно полезно, когда вы выполняете обнаружение столкновений в 2D-сетке.
Ответ №1:
Классы полезны, потому что у них могут быть методы и состояние / данные. Вообще говоря, если в вашем классе есть какие-либо данные, бессмысленно не создавать какие-либо объекты. Однако вы можете реализовать служебный класс, который состоит только из общедоступных статических функций. В таком случае вам не нужно создавать какой-либо объект.
Class CMyHelper
{
public:
static double calculateDistance(CPoint A, CPoint B);
static double calculateArea(double length, double width);
//...
private:
// You can even explictly say, I don't want make objects of this class.
// You'll get a compile-time error if someone tries.
CMyHelper();
CMyHelper(const CMyHelperamp;);
}
CPoint A(100, 200);
CPoint B(50, 100);
//Call static method without instantiation
CMyHelper::calculateDistance(A, B);
В вашем случае нет необходимости использовать статический класс и класс friend, как мы можем видеть.
Для меня класс friend — это последнее, к чему я буду прибегать. Согласно вашему описанию, вы можете сделать move()
be общедоступным методом player
класса, поскольку на самом деле «перемещается» игрок, а не map
. Кроме того, вам нужно разъяснить нам, что делает ваш map
класс.
Редактировать: Вы можете переместить координату игрока в класс player, если ваш класс map достаточно прост для удаления.
Class CPlayer
{
public:
void move()
{
// moves up, down, left, or right
// update m_position
}
}
private:
CCoordinate m_position;
}
Комментарии:
1. Вы можете создать класс и использовать его, не «создавая объекты» из него. Они называются статическими классами на случай, если вы захотите изучить это немного подробнее.
2. Понятно. Поэтому обычно я должен просто использовать объекты классов, которые я создаю, хотя в этом примере map.Move() имеет меньше смысла, чем player. Переместить ()? Мне нужна функция Move () для доступа к карте в любом случае, потому что координаты игрока являются частными данными карты. И спасибо за ответ.
3. Да, пожалуйста, используйте objects по своему усмотрению, поскольку в вашем случае нет никакой необходимости в статическом классе, как я вижу. Вы можете сделать объект map частью состояния вашего игрока, чтобы в move () вашего игрока вы могли получить доступ к координатам. Опять же, что находится внутри map, кроме corrdinates? Если ничего другого, вы можете переместить его в класс player и избавиться от map …
4. Ну, в Map действительно больше ничего нет. Я работаю над этим всего несколько часов, и это в основном практический проект для меня, чтобы привыкнуть к созданию и использованию классов agian.
Ответ №2:
Быть friends
— это самая тесная связь, которая может быть у двух классов. В общем, вы хотите избежать зависимостей, подразумеваемых в high coupling. Пусть ваш Player
класс использует общедоступный интерфейс Map
класса, если только вы не испытываете абсолютной необходимости использовать friend
.
Я бы сделал что-то вроде этого:
void MainLoop() {
// ... Read input and so on ...
player.Move(input);
map.Update(player.GetPosition());
}
Что касается эффективности: friend
на самом деле не имеет отношения к эффективности, поскольку проверки public / protected / private применяются во время компиляции. И даже если бы это было так, использование friend
для достижения эффективности было бы ярким примером преждевременной оптимизации, которой вам следует избегать.
Если в вашем классе есть некоторые или только статические члены, его можно использовать без создания экземпляра объекта. Более распространенный случай, когда у вас есть класс, но нет членов, является абстрактным интерфейсом. Эти классы предназначены для того, чтобы быть базовыми классами, определяющими интерфейс, который последующие классы затем наследуют и реализуют.
Комментарии:
1. Я не знал, что вы можете передавать функцию в качестве параметра.?
2. @vorbis5: Вы можете передавать указатели на функции, функторы (а в C 0x — лямбды). Однако в приведенном выше коде
input
предполагается, что это обычная переменная, иplayer.GetPosition()
это не функция, это возвращаемое функцией значение.
Ответ №3:
Как вы сказали, ответ субъективен, я бы предпочел сохранить его Move()
внутри player
класса, поскольку он выполняет действие над Player
.
Я не уверен в том, что Map
должен делать класс. Вы не упомянули подробности об этом.
Вы могли бы даже создать класс и использовать его, не создавая объект?
Да, возможно иметь класс и статические методы внутри класса, которые затем могут быть вызваны даже без создания объекта класса. Я не могу придумать практический пример, хотя.
Пример кода:
class MyClass
{
static int i;
public:
static void incrementCount()
{
i ;
}
static int returnCount()
{
return i;
}
};
int MyClass::i = 0;
int main()
{
int count;
//Do Some processing
MyClass::incrementCount();
//Do Some More processing
count = MyClass::returnCount();
return 0;
}
Комментарии:
1. Спасибо за ответ. Я использую Map, потому что он хранит координаты игрока в своих личных данных.
2. @vorbis5: Вы можете вызвать общедоступный метод, предоставляемый Map, чтобы обновить карту с подробными сведениями о перемещении.
Ответ №4:
Я собираюсь отреагировать на два общих аспекта вашего вопроса и как бы избежать особого случая, на который вы ссылаетесь. Вы не предоставили много подробностей, и я надеюсь, что общий пример поможет вам решить, нужно ли вам использовать friendship или нет.
Я немного запутался, когда использовать классы friend.
friend
больше похоже на protected
чем public
or private
в том, что оно предоставляет частичный или выборочный доступ. Обычно вам нужно использовать friend
объявление, когда вы конкретно хотите предоставить доступ к одному классу или функции, а не предоставлять доступ кому-либо.
Вы находитесь в затруднительном положении: вы должны предоставить доступ, чтобы вы не могли использовать private
; затем снова вы должны инкапсулировать свои данные, чтобы вы не могли использовать public
. В этих случаях friend
и protected
позволяют вам выбраться из этого затруднительного положения.
Основное различие между friend
и protected
заключается в том, что последний является открытым по количеству объектов, которым вы предоставляете доступ.
Если вам нужны более подробные сведения или примеры, в C FAQ есть отличный раздел о друзьях.
Я знаю, это может быть немного субъективно, но я как бы говорю в целом. Является ли использование класса friend более эффективным, чем прямое использование объекта Map?
Это не имеет ничего общего с субъективностью. Ограничения доступа используются только во время компиляции, а не во время выполнения программы. Следовательно, они не несут никаких накладных расходов во время выполнения. Если доступ к указанному элементу данных осуществляется через простую встроенную функцию получения, то это также не должно приводить к накладным расходам. В любом случае, я бы не стал начинать расследование этого, пока не исключу кучу других случаев, поскольку это, вероятно, не ваше узкое место.