Как получилось, декларация не нужна для концепции класса друга?
Я только недавно узнал о friend class
концепт в C++ (я немного погуглил, но этот ответ заставил меня смеяться, пока я не вспомнил самые важные части), и я пытаюсь включить его в проект, над которым я сейчас работаю. Конечный вопрос в конце выделен, но в целом меня смущает полное отсутствие предварительных объявлений в моем рабочем коде.
Все мои классы разделены через (под) папки и каждый в отдельный файл .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 ¶mFE = 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 ответа
Вы правы, декларация о дружбе похожа на предварительную декларацию.
Следующие компиляции:
class A;
class B
{
friend A;
};
или же
class B
{
friend class A;
};
это не
class B
{
friend A;
};
Это на самом деле не friend
декларация, которая форвард-декларирует class A
, но class
ключевое слово. Вот почему второй пример не работает, потому что он не знает, что A
является. Если вы объявите A
заранее, как в первом фрагменте, он может разрешить A
к объявлению класса.
friend class TLS;
Этот синтаксис является объявлением сам по себе, поэтому вам не нужно дополнительное предыдущее объявление типа. Обратите внимание, что friend
объявление немного отличается (особенно для функций) от объявления во вложенном пространстве имен.
В частности, если в окружающем пространстве имен нет также объявления, функция, объявленная в friend
объявление может быть найдено только путем поиска, зависящего от аргумента (и не может быть определено вне класса). То же самое относится и к классам, если только не существует объявления на уровне пространства имен, объявленный таким образом тип не будет доступен за пределами класса, объявляющего его другом.
class B {
friend class A;
};
//A foo(); // Error: A is not declared here!
class A;
A foo(); // Fine
Означает ли это, что объявление класса друга само по себе является предварительным объявлением?
да
Предварительное объявление не должно быть в начале файла следующим образом
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;
};
рекомендуемый синтаксис друга просто использует позже