I've run into a bit of a chicken and the egg scenario.
Say I have these two classes
class A{
public:
A(B& );
private:
B& ref;
};
class B{
public:
B(A& );
private:
A& ref;
};
Is there any way for me to initialize them? Because the fields are references, I have to bind them in the member initializer list so they can never be null. However, I can't make either one of them without the other, so I can't even supply the references.
Currently, I have two thoughts. The first is that I can switch one of the fields to a raw pointer, that way I can just supply a nullptr and bind it later in a method. However this weakens my null safety so I don't really want to do that. My second thought was that I could just declare a variable without initializing it, so something like
A foo;
B bar(foo);
foo(bar);
where I just construct it later. Unfortunately, this calls a default constructor on the first line, which isn't provided, so this doesn't work.
So I would like some advice on getting my current ideas to work, or if there's a built-in mechanism in C++ for this that I don't know about.
Its a chicken and egg problem. You need an A to create a B and you need a B to create an A.
However, if you always create an A and a B together, then I would suggest, as already mentioned in a comment, to wrap them in a class. Then you can use the member initializer list:
struct B;
struct A {
A(B& b) : ref(b) {}
B& ref;
};
struct B {
B(A& a) : ref(a) {}
A& ref;
};
struct AB {
A a;
B b;
AB() : a(b),b(a) {}
};
Using the reference to member b before it has been initialized is fine as long as A only stores the reference and does not read from it or call methods.
However, once they are wrapped in the same class it is kind of pointless to have them store references to each other.
Moreover reference members have certain unpleasant implications (eg no copies). Consider if thats what you really like or if perhaps pointers are fine.
If you are trying to create a loop dependency then at least one of the members will need to be a pointer. But it is otherwise fully possible to have this work by using forward declarations.
class B;
extern B b;
class A
{
public:
A(B & b)
: b(b)
{
}
private:
B & b;
};
class B
{
public:
B(A & a)
: a(a)
{
}
private:
A & a;
};
A a(b);
B b(a);
Related
I was looking to create a function that is capable of working with any Derived Object of A.
However in this example, I can't seem to be able to use B Object in a function that has a A Typing on it. Is there any way I pass B into the Function?
class A {
public:
A() {
}
};
class B :A {
public:
B() {
}
};
void function(A a) {
return;
}
int main(void) {
B b();
function(b);
}
I've commented on the fixes needed inline:
class A {
public:
A() {}
};
class B : public A { // public inheritance or A will be an inaccessible base of B
public:
B() {}
};
void function(const A& a) { // take a reference to an A to avoid copy-slicing
// ... work with the A part of the object you reference with `a`
}
int main() { // void not needed (but not an error as such)
B b; // not a function declaration anymore
function(b);
}
Actually you are lucky. You made two mistakes that caused passing b to the function fail, while in fact without that other mistakes you can pass b to the function but it would do the wrong thing silently.
First the two mistakes: B b(); declares a function. To declare a default constructed B you write B b;. Then B inherits privately, hence you cannot convert a B to an A. Thats what the error your code causes have told you.
However, after fixing those (and removing user declared constructors taht shouldnt be there when they do nothing)...
class A {};
class B : public A {};
void function(A a) {}
int main(void) {
B b;
function(b); // object slicing !!
}
This code compiles without errors, but usually it does the wrong thing!
Any B can be converted to an A because the inheritance is public, but what happens is object slicing: What is object slicing?. If B had any members not in A then they would all be lost when passing it to function. Its not an issue here because neither A nor B have any members, but in general you want to avoid objects to get sliced.
TL;DR: References / pointers are needed for polymorphism. Pass by (const) reference:
void function(const A& a) {} // does not modify a
void function(A& a) {} // modifies a
i'm working with c++.
I need to create two classes that refering to each other.
Something like this:
class A {
private:
B b;
//etc...
};
class B {
private:
A a;
//etc...
};
How can i do that?
Sorry for my bad English and thanks you for helping me :)
You can't do that even in principle, because a single A object would contain a B which contains another A, which contains another B and another A ...
If you just want a reference, you can simply do
class B; // forward declaration
class A {
B& b_; // reference
public:
explicit A(B& b) : b_(b) {}
};
class B {
A a_;
public:
B() : a_(*this) {}
};
Now each B contains an A which refers to the B in which it sits.
Do note however that you can't really do anything with b (or b_) inside A's constructor, because the object it refers to hasn't finished creating itself yet.
A pointer would also work - and of course A and B can both have references instead of B containing an immediate object.
First, sorry for thw poor title... I don't really know how to express with one
sentance what I mean... You are weclome to edit the title.
I have three classes A, B and C.
class A{
public:
A(double a):a_(a){}
private:
double a_;
}
class B{
public
B():a_ptr_(NULL){}
B(A const& a):a_ptr_(new A(a)){}
~B(){ delete a_ptr_; }
void set(A const& a){ a_ptr_ = new A(a); }
private:
A* a_ptr_;
}
class C{
public
C():a_ptr_(NULL){}
C(A const& a):a_ptr_(&a){}
void set(A const& a){ a_ptr_ = &a; }
private:
A* a_ptr_;
}
My problem is that if I do
B b(A(1.0));
C c(A(1.0));
the class A is instanciated twice for B (two creation constructor calls).
C::a_ptr_ is problematic. If I do :
B b;
C C;
{
A a(1.0);
b.set(a);
c.set(a);
}
I have the same problems outside the brackets.
I would like to find a way to store a pointer on A in B or C without
copying the class A too many times and without having undefined pointers.
I've found something with a move constructor but I've never used such.
Any idea ? Thx !
std::shared_ptr is exactly what you need. This class is used for storing one pointer in different places. The target object will be deleted after the last shared_ptr pointing to it is destroyed. Since you are clearing the memory in the destructor, your classes obtain ownership of the A object. You can use something like this:
class B{
public
B():a_ptr_(NULL){}
B(A * a): a_ptr_(a){ }
~B(){}//don't need to do anything here.
void set(A * a){ a_ptr_.reset(a); }
private:
std::shared_ptr<A> a_ptr_;
}
<...>
class C should be written in a similar manner
<...>
A * a = new a(1.0);
B b(a);
C c(a)
Now, if you want to make a constructor or set method that takes a by reference, you will not be able to avoid copying it. Also, in this case you can't safely take the address of this variable.
I have a few classes, each depends on using an instance of another object in a dependency chain. It looks something like this:
class A {} ;
class B
{
A& m_a;
public:
B(A& a) : m_a(a) { }
};
class C
{
B& m_b;
public:
C(B& b) : m_b(b) { }
};
To protect myself from holding dangling references because of order of destruction, I'm holding all of these in a container class, like this:
struct Data
{
Data() : m_b(m_a), m_c(m_b) { }
A m_a;
B m_b;
C m_c;
};
Assuming the order of the members in class Data matches the dependency order, is it safe to do so? Are there any pitfalls in holding these references which I'm missing?
It's OK. Class-members are initialized in order, in which they are declared, so:
m_a initialized -> m_b initialized with reference to m_a -> m_c initialized with reference to m_b.
No problem - C++ guarantees to construct the class members in the order they are declared, so you are safe.
what i have is two classes
//class A is a kind of config-class which have configuration details
//for class B
class A{
//....
};
class B{
public:
B(A const& _a)
:a(_a){}
private:
A const& a;
};
till this point everything is fine.
now i want is a B::configure(A const& _a) function so that i can dynamically pass the reference of configuration class A to class B which shall be assigned to the member variable a. but i'm not able to change the member variable B::a as it is a const&.
what can be the work around?
i think #Seth Carnegie's approach is better, i should use a pointer to class A inside class B in this way:
class B{
public:
B(A const& _a)
:a(_a){}
configure(A const& _a)
{ a = &_a; }
private:
A const* a;
};
You cannot alter a reference after it's been initialized, whether it is const or not. The const just keeps you from making alterations to the variable that the reference refers to. So to change the variable after the instance has been constructed, you'll have to use pointers rather than references.
Your grammar was rather unclear, tell me if I misunderstood the question.