Должен ли я использовать здесь класс friend?

#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?

Это не имеет ничего общего с субъективностью. Ограничения доступа используются только во время компиляции, а не во время выполнения программы. Следовательно, они не несут никаких накладных расходов во время выполнения. Если доступ к указанному элементу данных осуществляется через простую встроенную функцию получения, то это также не должно приводить к накладным расходам. В любом случае, я бы не стал начинать расследование этого, пока не исключу кучу других случаев, поскольку это, вероятно, не ваше узкое место.