Хорошо, позвольте мне начать с того, что это, вероятно, очень субъективно и спорно, и, вероятно, здесь не место (не стесняйтесь закрывать, если чувство взаимно). Сказав это, я смотрю на некоторый код и хочу прийти к стандартному подходу к композиции, поскольку кажется, что у разных людей разные стили - так что вот стили, которые я видел до сих пор (может быть больше ..) Конкретная проблема композиции, которую я рассматриваю, заключается в том, что класс B
владеет экземпляром класса A
, но A
должен знать этот экземпляр, чтобы он мог вызывать методы B
.
#include <iostream>
using namespace std;
namespace forward
{
class B;
class A
{
public:
A(B& b);
private:
B& inst;
};
class B
{
public:
B() : inst(*this) {}
void foo() { cout << "forward::B::foo()" << endl; }
private:
A inst;
};
A::A(B& b) : inst(b) { inst.foo(); }
}
namespace interface
{
struct IB
{
virtual void foo() = 0;
};
class A
{
public:
A(IB* b) : inst(b) { inst->foo(); }
private:
IB* inst;
};
class B : public IB
{
public:
B() : inst(this) {}
virtual void foo() { cout << "interface::B::foo()" << endl; }
private:
A inst;
};
}
namespace templated
{
template <typename IB>
class A
{
public:
A(IB& b) : inst(b) { inst.foo(); }
private:
IB& inst;
};
class B
{
public:
B() : inst(*this) {}
void foo() { cout << "templated::B::foo()" << endl; }
private:
A<B> inst;
};
}
int main(void)
{
forward::B b1;
interface::B b2;
templated::B b3;
return 0;
}
Из этого я вижу следующее (не полное):
объявления вперед Снижает необходимость включения заголовков в заголовки, однако вы не можете использовать тип, объявленный в этом заголовке вперед, т. е. при использовании должен быть доступен полный тип.
Интерфейсы Дополнительный багаж (конструкции базового класса, вызовы виртуальных функций и т. д.)
template Я не вижу никаких проблем с этим, кроме проблем с компиляцией (например, нелепые сообщения об ошибках и т. д.)
Теперь я предпочитаю шаблонный подход - я думаю, что он чистый и имеет то преимущество, что время компиляции принудительно. Итак, суть вопроса в том, есть ли что-то технически неправильное в этом подходе, и если нет, то почему вы должны использовать два других подхода?
РЕДАКТИРОВАТЬ: я думаю, что тривиальный пример не помог, в этом конкретном случае B является менеджером ресурсов и владеет различными компонентами, которые взаимосвязаны (A) - например, различные сетевые подключения и т. д. Все подкомпоненты могут получать доступ друг к другу через B - вся система раньше была набором синглетонов... Таким образом, единственная причина, по которой A знает о B, заключается в том, что он предоставляет доступ к какому-то другому компоненту, который нужен A...
Интересно, что в большинстве ответов рекомендуется пересылка, но я до сих пор не понимаю, почему это выгодно по сравнению с шаблонным подходом - есть ли какой-то врожденный страх перед использованием шаблонов в коде, отличном от простых общих функций?