Is there some way to initialize(?) member variable c of type C in the first part of the below example? Or must I use the new() method shown in the second part of the example?
Class B takes class A as an injected dependency. So does class C. Class B is additionally composed of class C.
How do I get the injected A to B's member C?
Part 1
class A { // ...; };
class C {
public:
C(A &a) : a(a) {} // constructor
};
// Does not work as is. Want to make compiler manage C lifetime.
class B {
public:
B(A &a); // constructor
C c(a); // member variable
};
// constructor
B::B(A &a) : a(a) {
}
Part 2
// Works, but requires programmer to manage C's lifetime.
class B {
public:
B(A &a); // constructor
C *c; // member variable
};
// constructor
B::B(A &a) : a(a) {
c = new C(a);
}
Several good answers below! My apologies for the confusing example. I have up-voted all of the good answers and questions. Unfortunately I can only mark one answer as the accepted answer, so I am choosing the first one which gave me the "ah-ha" moment in which I saw the solution to my real problem, which was more complex than my lame example here.
Member variables are initialized in constructor's initialization list (before body) so you need to do that:
B::B(A &a)
: c(a) // Calls constructor C(a) on member c
{}
You almost have it:
class B {
public:
B(A &a);
C c(a); //see note 1
};
B::B(A &a) : a(a) { //see note 2
}
Note 1:
There are two problems with C c(a); here:
a is not in scope. a only exists within the scope of the constructor, so c needs to be initialized from there.
Until C++11, non-static data member initializers (NSDMIs) were prohibited. Even in C++11, though, you must use an equals sign (C c = value;) or braces (C c{value};) when initializing an NSDMI.
Note 2:
You've almost got this right:
B::B(A &a) : a(a)
You're trying to initialize a data member called a with the argument given to the constructor. You actually want to initialize c like this, not a non-existent a:
B::B(A &a) : c(a)
The lifetime of c will be that of the instance of the B class. Using dynamic memory management is certainly not necessary.
"How do I get the injected A to B's member C?"
You can do so using B's constructor member initializer list
class B {
public:
B(A &a) : c(a) {
// ^^^^
}
C c; // <<< It's not possible to initialize members in their
// declaration.
};
The following:
C(A &a) : a(a) {}
will not compile since a (the first a in the initialization list) is not a member variable of C.
Same applies to the constructor of B.
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 have two classes which represent two different data types that can be converted back and forth. I want to have a constructor for each which takes an object of the other type so that I can more easily convert between the two, like so:
class A{
public:
A(B n){
//Do stuff converting n to type A
}
};
class B{
public:
B(A n){
//Do stuff converting n to type B
}
};
But it always fails to compile.
If you pass B by reference, you can use it as an incomplete type in A, with a forward declaration, like:
class B; // forward declaration
class A {
public:
A() = default;
A(B& n); // declare it here
};
class B {
public:
B() = default;
B(A n) {
//Do stuff converting n to type B
}
};
A::A(B& n) // define it here, B is fully visible now
{
//Do stuff converting n to type A
}
int main()
{
A a;
B b(a);
A another(b);
}
Note that you'd also need default constructors for at least A or B, as otherwise you cannot create an A without a B or the other way around. We also only declared the constructor in A, but defined it after B is fully visible (thanks #MattMcNabb for the comment). In this way, you'd be able to use any member of B in the constructor, since at that point B is fully visible.
The problem you are having is a common for beginners of C++ (or C for that matter).
The issue is that the signature A(B n) is seen by the compiler before the declaration of B is seen. But clearly, you cannot put B before A in the code, or you'd end up with the same type of situation.
This can be solved using forward declarations and references. My suggested default approach to this would be to declare these two entities as
class B;
class A {
public:
A(const B& n) {
// Do stuff converting n to type A
}
};
class B {
public:
B(const A& n) {
// Do stuff converting n to type B
}
};
Comming from Java, I have difficulty with the code below.
In my understanding b is just declared on line 3 but not instantiated.
What would be the text book way of creating an instance of B in class A?
class A {
private:
B b;
public:
A() {
//instantiate b here?
}
};
Edit: What if B does not have a default constructor?
You could explicitly initialize b in A's constructor's initialization list, for example
class A {
B b; // private
public:
A : b() {} // the compiler provides the equivalent of this if you don't
};
However, b would get instantiated automatically anyway. The above makes sense if you need to build a B with a non-default constructor, or if B cannot be default initialized:
class A {
B b; // private
public:
A : b(someParam) {}
};
It may be impossible to correctly initialize in the constructor's initialization list, in which case an assignment can be done in the body of the constructor:
class A {
B b; // private
public:
A {
b = somethingComplicated...; // assigns new value to default constructed B.
}
};
You have created an instance of b in line 3. This line is enough so that B's constructor is called. If you have code like this
class A {
private:
B *b;
public:
A() {
//instantiate b here?
}
};
then it would make sense to instantiate b in A's constructor like
A()
{
b = new B();
}
The correct phase your looking for is "C++ initialization list". This initialization list is called/initialized before the constructor is called
In case of Default constructor, compiler equvalient constructor will be A() : B() {}
A very good reference
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
At line 3, it is simply a declaration of B. However somewhere in your code where you have:
A a;
or
A a();
This calls the constructor of A. The internal b private member is full or garbage, as in not initialized. You are correct in that you can and probably should initialize member variable during construction where possible. There are two ways to do this:
A ()
{
b = B ();
}
Like you said:
or
A () : b (B())
{
}
The second version (initialization list) is slightly more efficient since it creates the new B object directly inside b. Whereas the first version creates a temporary and then moves that into b. This is the case when you initialize members from passed in parameters anyway (for non built in types). I'm making an assumption its the same in this case, but someone will be able to clarify.
I have the following C++-class:
// Header-File
class A
{
public:
A();
private:
B m_B;
C m_C;
};
// cpp-File
A::A()
: m_B(1)
{
m_B.doSomething();
m_B.doMore();
m_C = C(m_B.getSomeValue());
}
I now would like to avoid the class A to call any constructor of C m_C. Because on the last line in A::A(), I'm anyways going to initialize m_C myself because I need to prepare m_B first. I could provide an empty default constructor for class B. But that's not the idea.
I have already tried to add m_C(NULL) to the init-list of A::A(). Sometimes it worked, sometimes it said there was no constructor taking NULL as an argument.
So how can I have m_C left uninitialized? I know that with pointers, the m_C(NULL)-way works. And I don't want to allocate it dynamically using new.
Any idea is appreciated.
How about using technique described in this QA?
Prevent calls to default constructor for an array inside class
std::aligned_storage<sizeof(T[n]), alignof(T)>::type
Or, you also can consider using of union. AFAIK, unions will be initialized only with first named member's constructor.
For example,
union
{
uint8_t _nothing = 0;
C c;
};
According to the standard mentioned in the QA, c will be zero-initialized, and its constructor will not be called.
You can't.
All member variables are full constructed when the construcotr code block is entered. This means there constructors must be called.
But you can work around this restriction.
// Header-File
class A
{
struct Initer
{
Initer(B& b)
: m_b(b)
{
m_b.doSomething();
m_b.doMore();
}
operator int() // assuming getSomeValue() returns int.
{
return m_b.getSomeValue();
}
B& m_b;
};
public:
A();
private: // order important.
B m_B;
C m_C;
};
// cpp-File
A::A()
: m_B(1)
, m_C(Initer(m_B))
{
}
I don't see a good way to achieve what you want. This must be a workaround:
// Header-File
class A
{
public:
A();
private:
B m_B;
C m_C;
static int prepareC(B& b);
};
// cpp-File
A::A()
: m_B(1)
, m_C(prepareC(m_B))
{
}
int A::prepareC(B& b)
{
b.doSomething();
b.doMore();
return b.getSomeValue();
}
Please ensure that m_B.doSomething(), m_B.doMore() and m_B.getSomeValue() don't touch m_C (directly or indirectly).
As #Tobias correctly mentions, this solution depends on the order of initialization. You need to ensure that the definitions of m_B and m_C are in this order.
Updated the code according to #Loki's idea.
What you ask is forbidden - and correctly so. This ensures that every member is correctly initialized. Do not try to work around it - try to structure your classes that they work with it.
Idea:
C has a constructor that does nothing
C has an initialization method that makes the class usable
C tracks whether it has been initialized correctly or not and returns appropriate errors if used without initialization.
The pointer sounds like the only clean solution to me. The only other solution I see is to have a default constructor for C that does nothing and have an initialising method in C you call yourself later.
m_C.Initialise( m_B.getSomeValue() );
Easiest is storing pointers to a B and a C. These can be initialized to 0, omitting any construction. Be careful not to dereference a null pointer and delete it in the destructor of A (or use std::unique_ptr/boost::scoped_ptr).
But why not initialize m_B first (through a proper constructor call, not in A::A(), and then use that initialized B instance to initialize m_C? It will call for a small rewrite, but I bet it'll be worth the code cleanup.
If you don't want to allocate it dynamically using new for code clutter/exception safety reasons, you can use a std::unique_ptr or std::auto_ptr to solve this problem.
A solution that avoids new is to edit C to have a two-step initialization process. The constructor would then construct a "zombie" object, and you'd have to call an Initialize method on that m_C instance to finish your initialization. This is similar to the existing cases you found where you could pass NULL to the constructor, and later go back to initialize the object.
Edit:
I thought of this earlier (even though it looks much like other people's solutions). But I had to get some confirmation that this wouldn't break before I added this solution - C++ can be quite tricky, and I don't use it very often :)
This is cleaner than my other suggestions, and doesn't require you to mess with any implementation but that of A.
Simply use a static method as the middle-man on your initialization:
class A
{
public:
A();
private:
static int InitFromB(B& b)
{
b.doSomething();
b.doMore();
return b.getSomeValue();
}
// m_B must be initialized before m_C
B m_B;
C m_C;
};
A::A()
: m_B(1)
, m_C(InitFromB(m_B))
{
}
Note that this means you can't allow m_B to depend on the instance of A or C at all, whereas the solutions at the top of this answer might allow you to pass A or m_C into m_B's methods.
Just use comma expressions:
A::A()
: m_B(1)
, m_c(m_B.doSomething(), m_B.doMore(), m_B.getSomeValue())
{
}
Obviously, as others have explained, m_B better be declared before m_C else m_B.doSomething() invokes undefined behavior.
Here we have the building blocks:
#include <iostream>
class C
{
public:
C(int i){std::cout << "C::C(" << i << ")" << std::endl;}
};
class B
{
public:
B(int i){std::cout << "B::B(" << i << ")" << std::endl;}
void doSomething(){std::cout << "B::doSomething()" << std::endl;}
void doMore(){std::cout << "B::doMore()" << std::endl;}
int getSomeValue(){return 42;}
};
If you want to make a new kind of construction for B consider making a derived class:
class B1 : public B
{
public:
B1() : B(1)
{
doSomething();
doMore();
}
};
Now use the class B1 that is derived from B:
class A
{
private:
B1 _b;
C _c;
public:
A() : _c(_b.getSomeValue()){std::cout << "A::A()" << std::endl;}
};
And then:
int main()
{
A a;
}
Output:
B::B(1)
B::doSomething()
B::doMore()
C::C(42)
A::A()
I'm not used to c++ and I'm having a problem writing a constructor.
See this example, is a short version of the code I'm working on:
class B {
public:
B(int x);
}
class A {
public:
B b;
A(){
// here I have to initialize b
}
}
That throws a compiler error since I need to initialize b in A's constructor because B does not have a default constructor.
I think I have do it in the initialization list, but the B(int x) argument is a value I have to calculate with some algorithm, so I don't know how this should be properly done, or if I'm missing something or doing it wrong.
In other language like java I would have a reference to B and initialize it inside the A's constructor after the other code I need to get the value for the initialization.
What would be the right way to initialize b in this case?
Thanks!
You can invoke functions in your constructor initializer list
class B {
public:
B(int x);
}; // note semicolon
class A {
public:
B b;
A()
:b(calculateValue()) {
// here I have to initialize b
}
static int calculateValue() {
/* ... */
}
}; // note semicolon
Note that in the initializer list, the class is considered completely defined, so you can see members declared later on too. Also better not use non-static functions in the constructor initializer list, since not all members have yet been initialized at that point. A static member function call is fine.
You use an initializer list, something like this:
A() : b(f(x)) {}
#include<iostream>
class B {
public:
B(){} // A default constructor is a must, if you have other variations of constructor
B(int x){}
}; // class body ends with a semicolon
class A {
private:
B b;
public:
A(){
// here I have to initialize b
}
void write(){
std::cout<<"Awesome";
}
};
int main(){
A a;
a.write();
}
In C++, if you have a constructor that takes an argument, a default constructor is a must, unlike other languages as Java. That's all you need to change. Thanks.