Подтвердить что ты не робот

Почему декларация не нужна для концепции класса друзей?

Недавно я узнал о концепции friend class в С++ (я немного искал язык, но этот ответ заставлял меня смеяться, пока я не вспомнил наиболее важные части), и я пытаюсь включить его в проект, над которым я сейчас работаю. Конкретный вопрос выделен в конце, но в целом я смущен полным отсутствием форвардных деклараций в моем рабочем коде.

Все мои классы разделяются через (под) папки и каждый в отдельный файл .h и .cpp, но этого должно быть достаточно, чтобы получить представление о зависимостях:

// FE.h - no implementations - no .cpp file
class FE
{
    private:
       virtual void somePrivateFunc() = 0;
    // 90% virtual class, interface for further implementations
    friend class TLS;
};

// DummyFE.h
#include "FE.h"
class DummyFE :: public FE {
    /* singleton dummy */
    private:
        // constructor
    public:
        static DummyFE& instance();
};
// DummyFE.cpp
#include "DummyFE.h"
// all Dummy FE implementation

// ImplFE.h
#include "FE.h"
class ImplFE :: public FE { /* implemented */ };
// ImplFE.cpp
#include "FE.cpp"
// all Impl FE implementations


// SD.h - implements strategy design pattern
//        (real project has more than just FE class in here)
#include "FE.h"
#include "DummyFE.h"
class SD
{
    private:
        FE &localFE;
    public:
        SD(FE &paramFE = DummyFE::instance());
    // ... and all the other phun stuff ... 
    friend class TLS;
};
// SD.cpp - implementations
# include "SD.h"
/* SD implemented */

// TLS.h - implements strategy design pattern
           (on a higher level)
#include SD.h
class TLS{
    private:
        SD *subStrategy;
    public:
        void someFunctionRequiringFriendliness();
}

// TLS.cpp - implementations
#include "TLS.h"
void TLS::someFunctionRequiringFriendliness(){
    this->subStrategy->localFE.somePrivateFunc(); // ok!
}

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

Итак, чтобы попытаться сохранить это ясно, мой вопрос: При объявлении class TLS в качестве друга, почему нет явных форвардных деклараций? Означает ли это, что декларация friend class является декларацией о переходе в нее? Для меня, интуитивно, чего-то здесь не хватает... И поскольку он компилируется и работает нормально, может кто-то помочь исправить мою интуицию?: D

PS извините за такое длинное введение в вопрос и кучу кода. Пожалуйста, не комментируйте мою концепцию кода - друзья здесь хороши, я уверен, что это правильно для моего текущего проекта (это немного сложно увидеть из этого скелета). Я просто хотел бы знать, почему в любом месте не было необходимости в форвардной декларации.

4b9b3361

Ответ 1

Вы правы, объявление друга похоже на декларацию.

Следующие компиляции:

class A;
class B
{
   friend A;
};

или

class B
{
   friend class A;
};

это не так:

class B
{
   friend A;
};

На самом деле это не объявление friend, которое forward-declares class A, но ключевое слово class. Вот почему второй пример не работает, потому что он не знает, что такое A. Если вы объявите A заранее, как в первом фрагменте, он может разрешить A объявление класса.

Я стою исправлено.

Ответ 2

friend class TLS;

Этот синтаксис является объявлением сам по себе, поэтому вам не требуется дополнительное предыдущее объявление типа. Обратите внимание, что объявление friend несколько отличается (особенно для функций), чем объявление в охватывающем пространстве имен.

В частности, если в охватывающем пространстве имен нет объявления, функция, объявленная в объявлении friend, может быть найдена только с помощью зависимого от аргумента поиска (и не может быть определена вне класса). То же самое касается классов, если на уровне пространства имен нет объявления, объявленный тип не будет доступен за пределами класса, объявляя его как друга.

class B {
   friend class A;
};
//A foo();    // Error: A is not declared here!
class A;
A foo();      // Fine

Ответ 3

forward декларация не должна находиться в верхней части файла, как показано ниже.

class A;
class C;
class D;
class B
{
   A* a;
   C* c;
   D* d;
};

совпадает с

class B
{
   class A* a;
   class C* c;
   class D* d;
};

рекомендуемый синтаксис друга использует только

Ответ 4

Означает ли это, что объявление класса друга является прямым декларация все в нем сама?

Да