2016-02-22 2 views
0

У меня есть упрощенная версия реализации связанного списка, над которой я работал. Я хотел бы сохранить количество элементов (узлов) компонентов как частный член, а затем позволить конструктору и деструктору Component полностью обрабатывать переменную count.Проблема с друзьями: как предоставить частный доступ к внутреннему классу?

Однако я получаю ошибку компилятора (VS2015) о запрет на доступ к count любым функциям-членов (в том числе конструктора и деструктора), что я имею в Component:

«Количество»: необъявленный идентификатор

Почему заявление friend не предоставляет этот доступ в этом случае?

class Outer { 
private: 
    class Component; 
    friend class Component; 
public: 
    Outer() : count(0) {} 
    unsigned int size() { 
     return count; 
    } 
    void methodThatCreatesComponents() { 
     entryPoint = new Component(nullptr); 
     // I don't want to have to write ++count; every time I construct 
    } 
    void methodThatDeletesComponents() { 
     delete entryPoint; 
     // I don't want to have to write --count; every time I delete 
     entryPoint = nullptr; 
    } 
private: 
    unsigned int count; 
    Component* entryPoint; 
    class Component { 
    public: 
     Component(Component* next) { 
      ++count; 
     } 
     ~Component() { 
      --count; 
     } 
    private: 
     Component* next; 
    }; 
}; 
+0

C++ не позволяет автоматически внутренним классам иметь доступ к внешним классам. См. [Эта ссылка] (http://en.cppreference.com/w/cpp/language/nested_types). – callyalater

+1

Во-вторых, 'class Component() {...};' должен быть 'class Component {...}' (без круглых скобок). – callyalater

+0

@callyalater Вот почему я думал, что использование друга будет работать, но спасибо за ссылку, которая помогает. – Aposhian

ответ

0

Нужно квалифицировать count с надлежащим объемом.

Я предполагаю, что count ожидается static член Outer. Тогда для Вас использование:

Component(Component* next) { 
    ++Outer::count; 
} 
~Component() { 
    --Outer::count; 
} 

count Если предполагается быть не- static членом Outer, Component необходим экземпляр Object, чтобы иметь возможность доступа к переменной count члена.

+0

Не будет работать, поскольку 'count' не является статическим членом' Outer'. –

+0

Это не работает. Выдает ошибку «незаконная ссылка на нестатический элемент Outer :: count». – Aposhian

+0

@OlegAndriyanov, я предположил, что неверно, что 'count' является переменной-членом' static'. –

0

Вам необходимо получить доступ к закрытым членам внешнего класса с помощью указателя на внешний класс. Ошибки компилятора не связаны с уровнем доступа, они, вероятно, указывают на то, что «счет не был объявлен в области».

Следующая должно решить проблему:

class Component { 
public: 
    Component(Outer* outer, Component* next) : outer(outer) { 
     ++outer->count; 
    } 
    ~Component() { 
     --outer->count; 
    } 
private: 
    Outer* outer; 
    Component* next; 
}; 

P.S. Существует также Hacky способ получить указатель на внешний класс через offsetof:

class Component { 
public: 
    Component(Component* next) : outer(outer) { 
     ++outer()->count; 
    } 
    ~Component() { 
     --outer()->count; 
    } 
private: 
    Outer* outer() { 
     return (void*)this - offsetof(Outer, entryPoint); 
    } 

    Outer* outer; 
    Component* next; 
}; 
+0

Это будет работать, но довольно уродливо. Мне действительно нужно передавать 'this' в качестве параметра каждый раз, когда я вызываю конструктор? Кроме того, это добавляет дополнительный указатель на пространство памяти для каждого экземпляра Component ... Я бы почти просто установил пару операторов mutator с моими конструкторами/удалениями. – Aposhian

+1

@Aposhian Теперь ваш вопрос скорее о дизайне, чем о языке C++. Если вы хотите изменить 'count' каждый раз, когда узел вставлен/удален, я предпочел бы иметь функции' insert() 'и' remove() 'в' class Outer', которые будут делать 'count ++' и 'count- -'. Если «Компонент» представляет собой узел связанного списка, тогда ИМО он не должен знать ничего о своем контейнере, включая его размер. –

+1

@Aposhian не должно быть задачей «Outer :: Component» для настройки переменной-члена «Outer» в первую очередь IMO. Как заметил Олег, поместите вставку и удалите функции в классе 'Outer'. Предположительно, пользователь так и не увидит класс «Компонент», так зачем беспокоиться об этом другом. Сделайте 'Компонента' простой структурой и выполните логику в' Outer'. – rwols

0

Хорошо, я думаю, что я придумал подходящий метод, который работает на том, что Component не может знать о том, о экземпляре из Outer, что он находится внутри, не сохраняя this для каждого экземпляра. Использование вспомогательных функций:

class Outer { 
private: 
    class Component; 
public: 
    Outer() : count(0) {} 

    unsigned int size() { 
     return count; 
    } 
    void methodThatCreatesComponents() { 
     // other functionality 
     entryPoint = createComponent(nullptr); 
    } 
    void methodThatDeletesComponents() { 
     // other functionality 
     deleteComponent(entryPoint); 
    } 
private: 
    unsigned int count; 
    Component* entryPoint; 
    class Component { 
    public: 
     Component(Component* next) : next(next) {} 
     ~Component() {} 
    private: 
     Component* next; 
    }; 
    Component* createComponent(Component* next) { 
     ++count; 
     return new Component(next); 
    } 
    void deleteComponent(Component*& toDelete) { 
     --count; 
     delete toDelete; 
     toDelete = nullptr; 
    } 
}; 

Таким образом, я не придется беспокоиться об изменении счетчика каждый раз, когда я построить или уничтожить, или потоп this или других структур, предназначенных для компрометации вложенную структуру объекта. Другие ответы определенно помогли мне понять, что не так с моим восприятием внутренних классов. Чао!

Смежные вопросы