Как получилось, декларация не нужна для концепции класса друга? - PullRequest
11 голосов
/ 27 марта 2012

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

Все мои классы разделены через (sub-) папки и каждая из них в отдельный файл .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 извините за столь длинное введение в вопрос и кучу кода.Пожалуйста, не комментируйте мою концепцию кода - друзья здесь хороши, я уверен, что это правильно для моего текущего проекта (это немного трудно увидеть из этого скелета).Я просто хотел бы знать, почему нигде не требуется предварительное объявление.

Ответы [ 4 ]

7 голосов
/ 27 марта 2012
friend class TLS;

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

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

class B {
   friend class A;
};
//A foo();    // Error: A is not declared here!
class A;
A foo();      // Fine
6 голосов
/ 27 марта 2012

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

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

class A;
class B
{
   friend A;
};

или

class B
{
   friend class A;
};

это делаетне:

class B
{
   friend A;
};

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

Я исправлен.

2 голосов
/ 27 марта 2012

предварительное объявление не обязательно должно быть вверху файла следующим образом

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;
};

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

1 голос
/ 27 марта 2012

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

Да

...