Хорошо, позвольте мне начать с того, что это, вероятно, очень субъективно и аргументировано, и, вероятно, здесь нет места (не стесняйтесь закрываться, если это чувство взаимно).Сказав это, я смотрю на некоторый код и хочу прийти к стандартному подходу к композиции, поскольку кажется, что у разных людей разные стили - так что вот стили, которые я видел до сих пор (может быть больше..) Конкретная проблема компоновки, которую я рассматриваю, заключается в том, что класс 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;
}
Из этого я вижу следующее (не полное):
форвардные объявления Уменьшает необходимость включать заголовки в заголовки, однако вы не можете использовать тип, которыйявляется прямым объявленным в этом заголовке - т.е. полный тип должен быть доступен при использовании.
интерфейсы Дополнительный багаж (конструкции базового класса, вызовы виртуальных функций и т. Д.)
templated Я не вижу никаких проблем с этим, кроме компиляциипроблемы (т.е. нелепые сообщения об ошибках и т. д.)
Теперь я предпочитаю шаблонный подход - я думаю, что он чистый и имеет преимущество, заключающееся в том, что время компиляции является обязательным.Итак, суть вопроса в том, есть ли что-то технически неправильное в этом подходе, и если нет, то почему вы выбрали бы другие два подхода?
РЕДАКТИРОВАТЬ: я думаю, что тривиальный пример не помог, вв данном конкретном случае B является менеджером ресурсов и владеет различными компонентами, которые связаны между собой (A) - например, различными сетевыми соединениями и т. д. Все подкомпоненты могут обращаться друг к другу через B - вся система раньше была кучей синглетонов... Таким образом, единственная причина, по которой A знает о B, заключается в том, что он обеспечивает доступ к другому компоненту, который необходим A ...
Интересно, что большинство ответов рекомендует пересылку, но я до сих пор не понимаю, почемуэто выгодно по сравнению с шаблонным подходом - есть ли какой-то присущий страх использования шаблонов в коде, кроме простых обобщенных функций?