I'm stuck with a program I'm writing after a while of fidling around and completing "c++ through game programming" book.
The situation is as follows:
Class A
{
public:
A(int x)
protected:
int a;
};
A::A(int x):
a(x)
{}
Class B : public A
Class C : public B
{
public:
C(int x)
};
C::C(int x)
{
A(int x);
}
Am I able to call the constructor of class A in the constructor of class C?
From what I think I know: B is linked to A and C is linked to B so I should be able to get to the constructor of class A from C when I am able to reach member variables and functions by derriving it.
You can either try this:
class B : public A
{
public:
B(int x) : A(x) { }
};
class C : public B
{
public:
C(int x) : B(x) { }
};
Or if you're lazy (and using C++11):
class B : public A
{
public:
using A::A(int);
};
class C : public B
{
public:
using B::B(int);
};
This won't work:
class C : public B
{
public:
C(int x) : A(x) { }
};
main.cpp: In constructor ‘C::C(int)’:
main.cpp:23:16: error: type ‘A’ is not a direct base of ‘C’
C(int x) : A(x) { }
^
main.cpp:23:19: error: use of deleted function ‘B::B()’
C(int x) : A(x) { }
Related
I apologize if my question is dumb but i'm a beginner in c++. I'm working on diamond inheritance and i would like to know if it is possible to choose the specific parent class which will initilize an attribute for the child class.
To sum up, i would like this code to output B
Thank you for your answers !
PS: i'm working with c++98
#include <iostream>
class A
{
protected:
char m_char;
public:
A(): m_char('A'){};
char getChar(){return m_char;};
~A(){};
};
class B : virtual public A
{
private:
public:
B() {m_char = 'B';};
~B(){};
};
class C : virtual public A
{
private:
public:
C() {m_char = 'C';};
~C(){};
};
class D : public B, public C
{
private:
public:
D() {m_char = B::m_char;};
~D(){};
};
int main(void)
{
D d;
std::cout << d.getChar() << std::endl;
}
Virtual base classes are initialized In depth-first, left-to-right order. So you would need to name B second in your inheritance for D to call its constructor last and thus setting the variable to B at the end.
class D : public C, public B
m_char = B::m_char; is self assignment (there is only one m_char).
In virtual inheritance, it is the most derived class which initialize the virtual class (body does assignment).
How about being explicit in construction:
#include <iostream>
class A
{
protected:
char m_char;
public:
A() : m_char('A') {}
char getChar() const { return m_char; }
virtual ~A() {}
};
class B : virtual public A
{
public:
B() : A('B') {}
};
class C : virtual public A
{
public:
C() : A('C') {}
};
class D : public B, public C
{
public:
D() : A('B'), B(), C() {}
};
int main()
{
D d;
std::cout << d.getChar() << std::endl;
}
I end up with a multiple inheritance diamond problem with the situation that there is no default constructor in the base class.
struct A {
A(int x) {}
};
struct B : virtual public A {
using A::A;
};
struct C : virtual public A {
using A::A;
};
struct D : virtual public B, public C {
D(int x) : B(x), C(x) {}
};
int main() {
D d(1);
}
The compiler is complaining that:
error: constructor for 'D' must explicitly initialize the base
class 'A' which does not have a default constructor
D(int x) : B(x), C(x) {}
But, I don't really have access to A from D... How can I fix that? Thanks
You do have an access to A since you're inheriting from it.
You would have to call the constructor of A in order to construct the object D.
Your D constructor should look something like that :
D(int x) : A(x), B(x), C(x) {}
Because of the multiple inheritance, constructors of B and C would ignore the A(x) part and you will have only one object which is D.
When I construct an object D I need to include the constructors for A, B, and C in the initializer list. Is there any way to make it so that I don't need all three in the initializer list or not?
If I try to initialize D using only a constructor for B I get an error because I don't have a default constructor for A or C. If I add a default constructor for A and C I get issues with "i" being reinitialized with no value.
#include <iostream>
using namespace std;
class A
{
int i;
public:
A(int ii) :
i(ii)
{}
~A() { }
int getI() { return i; }
};
class B : public virtual A
{
public:
B(int ii) :
A(ii)
{ }
~B() { }
};
class C : public virtual A
{
public:
C(int ii) :
A(ii)
{ }
~C() { }
};
class D : public B, public C
{
public:
D(int ii) :
A(ii), B(ii), C(ii)
{ }
~D() { }
};
int main()
{
D d(45);
cout << d.getI() << endl;
}
If you add default constructors to A, B, and C, the implmentation of D becomes a bit simpler.
#include <iostream>
using namespace std;
class A
{
int i;
public:
A() : i(0) {}
A(int ii) : i(ii) {}
~A() { }
int getI() { return i; }
};
class B : public virtual A
{
public:
B() { }
B(int ii) : A(ii) { }
~B() { }
};
class C : public virtual A
{
public:
C() { }
C(int ii) : A(ii) { }
~C() { }
};
class D : public B, public C
{
public:
// Relies on default constructors of the other classes.
D() { }
// Relies on the default constructors of B and C.
D(int ii) : A(ii) { }
~D() { }
};
int main()
{
D d1(45);
D d2;
cout << d1.getI() << endl;
cout << d2.getI() << endl;
}
I'm afraid not. With virtual inheritance, your most-derived class must initialise the virtual base.
Read more here.
How about adding a default value to the A, B, C constructors, i.e.
A(int ii=0) :
I have a base class
class A
{
protected:
int a;
};
And a class which is derived:
class B : public A
{
B(int a_val)
: a{a_val} // not allowed by compiler?
{
}
};
I can solve the problem by:
B(int a_val)
{
a = a_val;
}
Is this "the solution", or can I do what I originally tried to do?
Of course, I could do this:
B(int a_val)
: A(a_val)
{
}
and change class A
A(int a_val)
: a{a_val}
{
}
However this isn't really "better" in the context of what I am doing.
In reply to an answer below (by swang): Can I therefore do this?
B(int a_val)
: A(), a{a_val}
{
}
When you do this:
class B : public A
{
B(int a_val)
: a{a_val} // not allowed by compiler?
{
}
};
You are trying to initialise a variable that doesn't belong to class B yet, so the right solution is
B(int a_val)
: A(a_val)
{
};
You can do this
B(int a_val)
{
a = a_val;
};
Because before a = a_val, the default construct of A has been called, and A::a has been default initialised.
Have a problem with multiple inheritance. I have solved diamond problem:
class A
{
int m;
int n;
public:
A(int x, int y)
{
m = x; n = y
}
fA() {}
};
class B : virtual public A // B has fA(),fB()
{
public:
B(int k) : A(1, k) {}
fB() {}
};
class C : virtual public A // C has fA(),fC()
{
public:
C(int k) : C(2, k) {}
fC() {}
};
class D : public B, public C // D has fA(),fB(),fC()
{
public:
D(int k) : B(k),C(k),A(3,k)
};
This is working well. Problem with this:
class S : public B // S has fA(),fB()
{
public:
S() : B(6) {}
};
Compilator shows me: "error: no matching function for call to `A::A()'"
This code is working, but it doesn't satisfied me:
class S : public B // S has fA(),fB()
{
public:
S() : B(6),A(1,6) {}
};
In virtual inheritance, the constructor of virtual base is called from the constructor of most derived class:
class S : public B // S has fA(),fB()
{
public:
S() : B(6) {}
}; // ^ A base class is initialized at this point, before B
This also means that other explicit calls to A's constructor in initialization-lists further down the inheritance chain are ignored:
class B : virtual public A // B has fA(),fB()
{
public:
B(int k) : A(1, k) {}
fB() {} // ^^^^^^^ this call is ignored when B is a part of S object
};
If there's no explicit call to virtual base's constructor in initialization list of most derived class, the compiler will (of course) try to call the default constructor. But A doesn't have one and that's your problem.
One solution you already discovered yourself. The other is to write default constructor for A.