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.
Related
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);
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 would like to ask what is the "best" way to share a parameter between an object and one of its members. I try to explain better my problem: I have a class A which needs a specific a parameter to be defined:
class A
{
public:
A(int);
~A();
private:
int ParameterA;
...
}
Also I have a second class B which contains an object of class A as its member and needs another parameter to be defined:
class B
{
public:
B(int);
~B();
private:
A MemberA;
int ParameterB;
...
}
Now my question is: if ParameterA and ParameterB are always equal, what is the "best" (clean) strategy to use?
I thought of three possibility
First option is to have two copies of the same value saved with
different names as in the code above. This seems to me quite
"dangerous", it would force me to always check that the two values
are equals.
Declare public the ParameterA, so class B can access it
Define a get function so class B can access ParameterA using the get function
Is there any other (better/standard) approach to deal with this case? What method should I follow?
You could declare ParameterA as a reference, and intialize it to reference ParameterB.
class A
{
public:
A(int& val) : ParameterA(val) {}
~A(){}
private:
int& ParameterA;
};
class B
{
public:
B(int val) : ParameterB(val), MemberA(ParameterB) {}
~B(){}
private:
int ParameterB;
A MemberA;
};
Your intuition about the danger of having two variables always holding the same value is right: this is at the very least a code smell and should be avoided.
The straightforward solution is inheritance:
class A {
public:
A(int a) : parameterA(a) {}
protected:
int parameterA;
};
class B : public A {
public:
B(int a) : A(a) {}
};
Of course, it depends on the context whether this solution is advisable, but it should always be the first to be evaluated.
The "best" way will probably depend on how A and B are used.
Of your options, I would avoid 1 and 2 if you can but I think 3 might be a reasonable option unless the parameter is really not something you want to expose. If you want to keep the parameter private you could make B a friend of A.
Another option is to take the ownership of the parameter away from A. You could define the parameter outside the class (maybe inside another class) and pass a reference or pointer into B and A.
A more flexible approach might be to use a shared pointer but you might not need that flexibility in practice. By using a shared_ptr you do not restrict what you can do with your classes like references would and it doesn't tie the lifetime of A or B to the lifetime of an external object. And can easily create a self contained A on its own if you want:
#include <memory>
using SharedInt = std::shared_ptr<int>;
class A {
public:
A(SharedInt parameter) : parameter_(parameter) {}
private:
SharedInt parameter_;
};
class B {
public:
B(SharedInt parameter) : a_(parameter), parameter_(parameter) {}
private:
A a_;
SharedInt parameter_;
};
int main() {
auto b = B(std::make_shared<int>(3));
auto a = A(std::make_shared<int>(7));
}
But I might be tempted to go for a more restrictive design first and only move to shared pointers if needed.
I have the code:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test() says "class A", but how I can call method getString() from class B and not A?
Thanks!
The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this
A a;
what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!
To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.
Since a pointer example was already shown by #Nawaz, I will give another using a reference:
class C{
public:
C() : a(b) { // references must be initialized in the constructor initializer list
}
std::string test() {return a.getString();}
private:
B b; // moved to class scope to ensure that it stays alive
A& a;
};
You need to implement like this:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
This will call getString() from class B and not A.
What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).
Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.
You are slicing therefore it will not work. a is an A it is not a B.
To work your class member variable a must be a pointer or a reference.
As a pointer
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
As a reference
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
Of course the code I have produced leaks but will work with the virtual function.