Как создать хорошо инкапсулированные классы при использовании неупорядоченного набора/карты в c ?

#c #design-patterns #encapsulation #unordered-map #unordered-set

Вопрос:

Я просматривал несколько руководств о том, как создать неупорядоченный набор для класса/структуры. Я нашел этот простой для понимания код (как разработчик Java), который делает свое дело:

 #include <iostream>
#include <unordered_set>
using namespace std;

struct Node{
    int val;
  
    bool operator==(const Nodeamp; n) const{
        return (this->val == n.val);
    }
};

class HashFunction{
    public:
        size_t operator()(const Nodeamp; n) const{
            return n.val;
        }
};

int main(){
    Node n1 = { 1 }, n2 = { 2 },
         n3 = { 3 }, n4 = { 4 };

    unordered_set<Node, HashFunction> us;
    us.insert(n1);
    us.insert(n2);
    us.insert(n3);
    us.insert(n4);
    
    for (auto node : us){
        cout << node.val << " ";
    }
    cout << endl;
    return 0;
}
 

Мне было интересно, можем ли мы создать struct Node класс a, сделать int val закрытое поле a и добавить unordered_set<Node, HashFunction> neighbours в качестве поля в Node класс.

Если нет, то какова хорошая практика, чтобы классы/структуры были хорошо инкапсулированы и имели наборы/поля карт для классов?

Комментарии:

1. Обратите внимание, что Node в C означает фактический объект, а не указатель, как в Java. Коллекция «соседей» нуждается во взаимосвязи «многие ко многим», которая может быть реализована только с помощью указателей.

2. Структура-это просто класс, по умолчанию открытый для всех участников. Если вы сделали val закрытым, то хэш класса не сможет его вернуть.

3. @BenVoigt спасибо за комментарий, вы имеете в виду, что набор «соседей» должен иметь узел* в качестве шаблона?

4. @sucksatnetworking спасибо за комментарий. Теперь я попытаюсь сделать «Узел» классом.

Ответ №1:

Здесь есть несколько вопросов, поэтому я постараюсь ответить на них по порядку:

может сделать struct Node класс а

Да, struct и class отличаются только разрешениями по умолчанию (в struct том, что есть public , если не указано иное, в class том, что они есть private ). Итак, это код, идентичный тому, что вы написали:

 class Node{
public:
    int val;
  
    bool operator==(const Nodeamp; n) const{
        return (this->val == n.val);
    }
};
 

сделайте поле int val закрытым и добавьте unordered_set<Node, HashFunction> neighbours в качестве поля в Node класс

Да, ты можешь. Самый простой способ, который я могу придумать, чтобы сделать этот переход из кода, который вы написали,-это сделать HashFunction его подклассом Node . Например:

 class Node {
    class HashFunction {
        public:
            size_t operator()(const Nodeamp; n) const{
                return n.val;
            }
    };

public:
    Node(int _val) : val(_val) {}

    bool operator==(const Nodeamp; n) const{
        return (this->val == n.val);
    }

    // More methods here

private:
    int val;
    unordered_set<Node, HashFunction> neighbours;
};
 

Если нет, то какова хорошая практика, чтобы классы/структуры были хорошо инкапсулированы и имели наборы/поля карт для классов?

Я предполагаю, что в данном случае это несколько немой вопрос, но общий ответ заключается в том, чтобы предоставить только минимально необходимый интерфейс. Например, прямо сейчас HushFunction осознает внутреннее содержание Node . чтобы увеличить инкапсуляцию, мы могли бы добавить hush метод Node и HushFunction вызвать этот метод. Таким образом, если содержание Node меняется, ничто за пределами Node не должно об этом знать.