C++ circular dependency: What should the constructor look like?
I read through a lot of circular dependency topics but all of them seem to be concerned with the declaration. I am interested how to construct the mutually depended objects and if there are potential pitfalls with my approach. Consider this simple example:
#include <iostream>
#include <vector>
using namespace std;
class A; //Forward declaration
class B{
public:
B(string name, A* a):myA(a), name(name){
cout << "Works with pointer" << endl;
};
private:
A* myA;
string name;
};
class A{
public:
A(){
cout << "Constructing A" << endl;
if(bs.empty()) cout << "Vector is empty" << endl;
bs.push_back(B("First", this));
cout << "Array has " << bs.size() << " elements." << endl;
};
private:
std::vector<B> bs;
};
int main() {
cout << "Start" << endl;
A开发者_如何转开发 a;
cout << "Ok." << endl;
return 0;
}
Is there anything that I could do to avoid the A*
pointer in B
?
Ideally I would like to have a reference, but if I change the constructor of B
to B(string name, A& a)
and then change the push_back to bs.bush_back(B("First", *this));
I get an error: non-static reference member 'A& B::myA', can't use default assignment operator
. See the modified example
As far as I can tell the operator=
that is synthesized by the compiler does not fit here. How would the proper operator=
look like? Or am I going the wrong direction all together?
When you use a type in a standard container, like vector
the type needs to be CopyConstructible and Assignable. If your type has pointer members then these will work fine with an implicitly defined copy assignment operator but this is not the case with reference members as references can't be rebound.
If you want your type to work in a container it is much simpler to stick with pointer members. It's not obvious whether you can define a copy assignment operator that makes sense in your particular case, in general it isn't.
You couldn't use a reference there even with a user-defined assignment-operator, because references cannot be rebound once they are initialized. Using a pointer here is the simplest approach.
In this case (and only in this case), you could consider making B
a template..
template <typename SomeA>
class B{
public:
B(string name, SomeA& a):myA(a), name(name){
cout << "Works with reference" << endl;
};
private:
boost::optional<SomeA&> myA;
string name;
};
class A{
public:
A(){
cout << "Constructing A" << endl;
if(bs.empty()) cout << "Vector is empty" << endl;
bs.push_back(B<A>("First", *this));
cout << "Array has " << bs.size() << " elements." << endl;
};
private:
std::vector<B<A> > bs;
};
This suggestion is purely without any context...
精彩评论