How to initialize const circular reference members - c++

For example, I have two classes
class Foo;
class Bar;
class Foo {
const Bar &m_bar;
...
};
class Bar {
const Foo &m_foo;
...
};
Let foo is object of Foo and bar is object of Bar. Is there any way (normal or "hacking") to create/initialize foo and bar that their members m_bar and m_foo would referenced to each other (I mean foo.m_bar is bar and bar.m_foo is 'foo')?
It is allowed to add any members to Foo and Bar, to add parents for them, to make they templates and so on.

What is the linkage of foo and bar? If they have external
linkage, you can write something like:
extern Foo foo;
extern Bar bar;
Foo foo( bar );
Bar bar( foo );
(I'm assuming here that it is the constructors which set the
reference to a parameter.)
This supposes namespace scope and static lifetime, of course
(but an anonymous namespace is fine).
If they are class members, there's no problem either:
class Together
{
Foo foo;
Bar bar;
public:
Together() : foo( bar ), bar( foo ) {}
};
If they're local variables (no binding), I don't think there's
a solution.
EDIT:
Actually, the local variables have a simple solution: just
define a local class which has them as members, and use it.

This can't work if i understand your Problem correctly, since to create an Object Bar you need Foo and vice versa.
You must not use References but an Pointer instead. Where you can create both Objects separatley and then set Bar to Foo and Foo to Bar.
class Foo
{
public:
Foo();
void setBar( const Bar* bar ){ _bar = bar; }
private:
const Bar* _bar;
}
// class Bar analog to Foo
void xxx:something(void)
{
Foo* f = new Foo;
Bar* b = nee Bar;
f->setBar(b);
b->setBar(f);
...
}

Related

Initialize a C++ class using its constructor inside another Classes constructor that references it

I have a class Foo that references Bar:
class Foo {
Bar &bar;
};
and bar requires an int& to be constructed:
Class Bar {
Bar(int& required_int);
}
I want to be able to initialize Bar when I initalize Foo, but I cannot seem to do so using either of the following:
Foo::Foo(int &my_int) : bar(my_int) {
//...
}
Foo::Foo(int &my_int) : bar(new Bar(my_int)) {
//...
}
Because the compiler complains that whatever is inside bar(...) must be an lvalue. Is this initalization chaining possible? I don't see how bar(...) could ever contain an lvalue if my instance of Bar doesn't exist yet.
class Foo {
Bar & bar;
};
Here bar can only refer to an existing Bar object as it's a reference. You cannot initialize it yourself in Foo class. So, a valid ctor would be similar to this:
Foo::Foo(Bar & existingBar) : bar(existingBar){}
If you want Foo class to have its own independent Bar object, then remove the reference and initialize it like you're doing already.

How to share an object between two classes

I have two classes, Foo and Bar. They both contain a pointer to a Baz object. I want the Baz pointers in both an instance of Foo and an Instance of Bar to point to the same Baz object.
A Baz object has a member called name with getter and setter functions.
A Foo object contains a Bar object.
A Bar object has a method to print the name of the Baz object.
The Baz objects name must be set in the scope of Foo.
This is what I have tried:
In the constructor of Foo, it sets the name of this bazA, and sets the bazB belonging to bar to be equal to the bazA belonging to Foo.
//Foo.h
class Foo {
public:
explicit Foo();
Baz* bazA;
Bar bar;
}
//Foo.cpp
Foo::Foo()
{
this->bazA->setName("hello");
this->bar.bazB = bazA;
}
//Bar.h
class Bar{
public:
Baz* bazB;
void printName ();
}
//Bar.cpp
void Bar::printName ()
{
std::cout << "name: " << bazB->getName();
//Should print out "name: hello"
}
When I do this:
//Main.cpp
Foo foo;
foo.bar.printName();
The program crashes because the name member has not been initialised in the Baz object that belongs to the Bar object.
But the Baz object belonging to Bar should be the same Baz object that belongs to Foo, which has had its name set, so it should work.
Why am I getting this error?
How can I correctly share a Baz object between the Foo and Bar classes?
The code you have to share the objects is correct: Foo creates the Baz, then passes it to the Bar. The issue is you are not constructing the Baz properly:
Foo::Foo()
{
this->bazA->setName("hello"); // crash because bazA hasn't had memory allocated
this->bar.bazB = bazA; // setting bazB to invalid memory
}
Instead, you should just have an object of Baz in Foo, and share it with Bar:
class Foo {
public:
Foo();
Baz bazA;
Bar bar;
}
Foo::Foo()
{
bazA.setName("hello");
bar.bazB = &bazA;
}
Even better, Bar's constructor should take a Baz reference instead:
class Bar
{
public:
Bar(Baz& b) : bazB(b){}
private:
Baz& bazB;
};
Foo::Foo()
: bazA(), bar(bazA)
{
bazA.setName("hello");
}
Here I assumed that Class and Public were typos and corrected them.

C++ function definition and variable declaration mismatch?

Consider this very simple code:
#include <memory>
class Foo
{
public:
Foo() {};
};
class Bar
{
public:
Bar( const std::shared_ptr<Foo>& foo ) {}
};
int main()
{
Foo* foo = new Foo;
Bar bar( std::shared_ptr<Foo>( foo ) );
return 0;
}
Why does Visual Studio reports
warning C4930: 'Bar bar(std::shared_ptr<Foo>)': prototyped function not called (was a variable definition intended?)
and there is no bar object created...how can this line Bar bar( std::shared_ptr<Foo>( foo ) ); be interpreted as a function definition?
I checked Do the parentheses after the type name make a difference with new? and also C++: warning: C4930: prototyped function not called (was a variable definition intended?), but I feel my problem is different here as I did not use the syntax Foo() nor Bar().
Edit: Note that it successfully compiles:
Foo* foo = new Foo;
std::shared_ptr<Foo> fooPtr( foo );
Bar bar( fooPtr );
This issue is about C++'s most vexing parse. The statement:
Bar bar( std::shared_ptr<Foo>( foo ) );
declares a function called bar that returns Bar and takes an argument called foo of type std::shared_ptr<Foo>.
The innermost parenthesis have no effect. It is as if you would have written the following:
Bar bar( std::shared_ptr<Foo> foo);
Assuming C++11 (since you are already using std::shared_ptr) you could use the brace syntax instead of parenthesis:
Bar bar(std::shared_ptr<Foo>{foo});
This would actually construct an object bar of type Bar, since the statement above can't be interpreted as a declaration because of the braces.

Passing a const pointer... do I need to do it?

I have a struct of Foo:
struct Foo
{
};
I have a struct of Bar:
struct Bar
{
};
They are handled by 2 more structs which maintain (add/remove) a pointer array of each:
struct FooContainer
{
Foo** FooList;
// add(), remove() etc
};
struct BarContainer
{
Bar** BarList;
// add(), remove() etc
};
Now, what I WANT is another struct called Baz which links (in a one-to-many fashion) Foo to Baz. I can't (for reasons not explained here) refer to them by index, it must be by pointer/reference.
Something like this:
struct Baz
{
Foo* foo;
Bar* bar;
};
If I wanted to add a constructor to Baz which took these non-const pointers, how would I do it?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
Do I pass the pointers into the constructor as const and then do something with them as I would if I were passing a reference to a struct? I then get issues with trying to set the value of a non-const pointer to a const pointer.
I hope this question makes sense...
Edit: Should I use reference instead of pointer?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
That is correct, you don't want to store constant pointers. However, it does not prevent you to store pointers to const, which is not the same thing.
This sounds confusing, so here is an illustration using your Baz example:
struct Baz
{
const Foo* foo;
const Bar* bar;
Baz(const Foo* newFoo, const Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(const Foo* newFoo) { foo = newFoo; }
void setBar(const Bar* newBar) { bar = newBar; }
};
everything is going to compile fine: it's Foo and Bar pointed to by foo and bar that are const, not the pointers themselves, which leaves you free to change the pointers as you wish.
This, on the other hand, is not going to compile:
struct Baz
{ // Note how const has moved to the other side of the asterisk
Foo* const foo;
Bar* const bar;
Baz(Foo* newFoo, Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(Foo* newFoo) { foo = newFoo; } // BROKEN!!!
void setBar(Bar* newBar) { bar = newBar; } // BROKEN!!!
};
Now the pointer, not the "pointee", is const, preventing you from changing foo or bar members.

How to forward declare a C++ class as inheriting from another class?

I know that I can forward declare a class as follows:
class Foo;
// ... now I can use Foo*
However, can I do something like this:
class Bar {
public:
virtual void someFunc();
};
// ... somehow forward declare Class Foo as : public Bar here
someFunc(Foo* foo) {
foo -> someFunc();
}
class Foo: public Bar {
}
?
Thanks!
You can forward declare Bar as class Bar; and change the signature of someFunc to take a Bar* as parameter. Since someFunc() is a virtual method in the base class, it should work.
After your forward declaration Foo becomes an incomplete type and it will remain incomplete until you provide the definition of Foo.
While the Foo is incomplete any attempt to dereference a pointer to Foo is ill-formed. So to write
foo->someFunc();
you need to provide Foo's definition.