I have a base class 'A' which has a subclass 'B' which has a subclass 'C' which has a subclass 'D'.
I want D to call 'A's constructor,
D(int x,int y):A(x,y){};
but I am getting the error message:
error C2614: 'D' : illegal member initialization: 'A' is not a base or member.
D can call any of 'C's constructors fine but that is not what I want.
Any help would be super appreciated.
You're stuck, that's the way C++ works - you only get to call the constructor of your immediate parent. You can daisy chain them so that D calls C's constructor which calls B's constructor which calls A's constructor.
D(int x,int y):C(x,y){};
C(int x,int y):B(x,y){};
B(int x,int y):A(x,y){};
As Mark Ransom's answer states, a derived class is only allowed to call its base class' constructor.
In your case, you can solve the problem by passing along the constructor arguments to D down the inheritance hierarchy until A's constructor is called by B with those arguments.
Another option is to create a protected function, say A::init( args ) that can be called by D directly.
In addition to the option of passing arguments down the inheritance hierarchy or having a protected member function in the base class, you could also solve this by using virtual inheritance. With virtual inheritance all base class constructors are called directly from the derived class so you don't have to go through the inheritance chain.
class A
{
public: A(){}
public: A(int x, int y){}
};
class B : public virtual A
{
public: B(){}
};
class C : public virtual B
{
public: C(){}
};
class D : public virtual C
{
public: D(int x,int y):A(x,y){};
};
Related
I have a base class:
class Base {
protected:
int m_a;
virtual void foo() = 0;
}
And a derived class(es)
class Derived : public Base {
public:
Derived(int a);
}
The base class is abstract, so only derived classes can be created.
How is the better way to implement the derived Ctor?
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
Or
Derived::Derived(int a) { m_a = a;}
Base::Base(){}
Is it better to remove the member from Base constructor, since it cannot be created alone, OR to keep it on the Base constructor to stay the assignment for him?
Your first solution- giving the base class an explicit constructor - is preferable as general pattern:
it avoids other classes inherited from Base forgetting to initialize m_a. Instead, the signature of the class indicates initialization is required.
if multiple classes inherit from base, and initialization is more complex (e.g. a range check) , this code - and policy - is not distributed over multiple derived classes
if m_a is immutable, constructor initialization is required
derived classes might have more than one CTor, more places to forget
Only downside: a little more typing - as long as you don't count the additional "I'm a little lazy today so don't forget to init m_a in all derived classes constructors"
The "signature announces the requirements" is IMO sufficient to make this the default pattern, so is "the other way requires making m_a protected", as mentioned in the comments.
I would prefer :
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
By this way you make your code more encapsulated and Base members took care about its init list, there can be some more init logic in base class constructor depending on m_a instead of just initing m_a. In this case you pass initial value to your base constructor and then derived class in his constructor has initialized constructor of base class.
You should try to pass init values to your Base class, imagine you have 5 Derived classes and you need to init base class at all of yours derived ctors.
Consider the following code:
class A {
};
class B : public A {
};
class C : public B{
public:
C() : A() {} // ERROR, A is not a direct base of B
};
In this case GCC (4.8.1, C++99) gives me the correct error (I understand this behavior):
prog.cpp:12:8: error: type ‘a’ is not a direct base of ‘c’
However if the inheritance between b and a is virtual, this does not happen:
class A {
};
class B : virtual public A {
};
class C : public B{
public:
C() : A() {} // OK with virtual inheritance
};
Why does this work?
Is A now considered a direct base to C by the compiler?
In general, because this is how C++ tries to resolve the diamond inheritance problem http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem (whether or it is a good or bad solution is left as an exercise to the reader).
All inheritance is a combination of an is-a and a has-a relationship...you must instantiate an instance of the parent. If you have the following classes:
class a;
class b : a;
class c : a;
class d : b,c;
Then you've instantiated an a for each b and c. d will not know which a to use.
C++ solves this by allowing virtual inheritance, which is high-overhead inheritance that allows b and c to share the same a if inherited in d (it is much more complicated than that, but you can read up on that on your own).
The most derived type in the chain needs to be able to override the instantiation of the shared class to control disparities in the way that the shared class is inherited in the parent classes. Take the following example:
class a {int x; public: a(int xx) {x=xx;} int get_x() {return x;}};
class b : public virtual a { public: b(): a(10){}};
class c : public virtual a { public: c(): a(15){}};
class d : public virtual b, public virtual c {public: d() : a (20) {}};
int main() {
d dd;
std::cout << dd.get_x() << std::endl;//20, d's constructor "wins"
return 0;
}
If d did not define what a was instantiated as, it would have definitions for conflicting instantiations (from b and c). C++ handles this by forcing the most derived class in the inheritance chain to instantiate all parent classes (the above would barf if d did NOT explicitly instantiate a, though if a supplied a default constructor that could be implicitly used) and ignoring all parent instantiations.
Why does this work?
According to the standard (10.1.4 in the FIDS), "for each distinct baseclass that is specified virtual, the most derived object shall contain a single base class subobject of that type".
Virtual base is shared between all classes that derive from it for the instance of the object. Since a constructor may only be called once for a given instaniation of an object, you have to explicitly call the constructor in the most derived class because the compiler doesn't know how many classes share the virtual base. This is because the compiler will start from the most base class's constructor and work to the most derived class. Classes that inherit from a virtual base class directly, will not, by the standard, call their virtual base classes constructor, so it must be called explicitly.
From N3337, 12.6.2
Initializing bases and members
In the definition of a constructor for a class, initializers for direct and virtual base subobjects and non-static data members can be specified by a ctor-initializer, which has the form
Perhaps someone who has better version of Standard can verify this.
I have 2 base classes (B1 and B2) which are derived from common Base class(B), where they have a common variable (let: int x; from base B), in 1st base x=0, in the 2nd base x=10 (default values given in B1,B2 constructors).
Visually:
class B
{
int x;
protected:
B(int x) : x{x}{}
};
class B1 : public B
{
protected:
B1() : B(0){}
};
class B2 : public B
{
protected:
B2() : B(10){}
};
Now if I derive one more class:
class D : virtual public B1, virtual public B2
{
public:
D() : B1{}, B2{}{}
};
Here only one copy of x will be available as per virtual concept, now if I try to access x value with derived class object which instance of x I will get in O/p (x=0 or x=10), and why?
In order to use virtual inheritance, base B must be declared as virtual in both B1 and B2. Without that, you have non-virtual inheritance of B.
If you have non-virtual inheritance, then you have two B bases in D, so you can't access x in D without qualifying it as B1::x or B2::x
If you have virtual inheritance, then you only have one B and one x, so the two assignments to it (x=0 and x=10) will happen in whichever order you did them in, and whichever one was later will overwrite the value set by the earlier one (much as with a simple variable x with two assignments).
In your setup as you have it, B is not actually inherited virtually, because you would have to declare virtual inheritance for B in both B1 and B2 (it always has to happen at the lowest level if the two "branches" are expected to be merged higher up in the class inheritance hierarchy), i.e.
class B1 : virtual public B
{
protected:
B1() : B(0){}
};
class B2 : virtual public B
{
protected:
B2() : B(10){}
};
If you do that, initialization of B would be completely different, because there are special rules for the construction of virtual base classes:
In virtual inheritance, the virtual base class is always initialized by the most derived class. Thus, as you have implemented the constructor of D as
D() : B1(), B2(){}
and therefore don't call your B constructor explicitly, the compiler will assume that you want to call Bs default constructor. But your class B does not have a default constructor, so you would get a compiler error like this:
prog.cpp: In constructor ‘D::D()’:
prog.cpp:31:20: error: no matching function for call to ‘B::B()’
D() : B1(), B2(){}
^
Therefore, you would have to do something like
class D : public B1, public B2
{
public:
D() : B(99), B1(), B2(){}
};
and this also solves your question: The value of x will be whatever the most derived class wants it to be (99 in this case). Thus, there is no ambiguity.
PS: You also see, your question is at the heart of why it makes sense to have the special rule about virtual base class construction by the most derived class.
#include<iostream.h>
class A{
public:
int i;
A(int j=3):i(j){}
};
class B:virtual public A{
public:
B(int j=2):A(j){}
};
class C:virtual public A{
public:
C(int j=1):A(j){}
};
class D:public B, public C {
public:
D(int j=0):A(j), B(j+1), C(j+2){}
};
int main()
{
D d;
cout<<d.i;
return 0;
}
I am not being able to understand how the final output is zero. Every time j is initialized in default way to some fixed value, how is the value initialized in the constructor of class D being passed to class A?
Since A is a virtual base class, it should be constructed only once, so it is not possible to create it with different constructor parameters, and the C++ compiler has to choose one way of creating a base class.
The obvious question is: which one is used?
And the rule is: the one specified in the most derived class that inherits A directly.
The initialization order is simple: first A (with the parameter value from D constructor initialization list), then B (it is D's first ancestor; and it uses the instance of A created before), then C (and it shares the same A instance), finally D (and it also shares the same A object as B and C).
The rule with virtual base inheritance is:
"The most derived class in a hierarchy must construct a virtual base"
In your case, from the most derived class D You explicitly called the constructor of A by passing an argument 0 So it sets the i to 0. As mentioned in rule virtual base class is constructed through most derived class only and the other constructor calls through intermediate hierarchy have no effect since it is only constructed once.
The order of calling is:
A(int)
B(int)
C(int)
Good Read:
Why virtual base class constructors called first?
I am using a class say baseClass, from which I derive another class derivedClass. I have a problem definition that says, apart from others:
i) A member - object initialiser should be used to initialise a data member, say var1, that is declared in the base class.
ii) i) is done inside a base class constructor. It says, this has to be invoked only via a derived class constructor.
iii) The base class is an abstract class, whose objects cannot be created. But, I have a third class, inside which, I use:
baseClass *baseObjects[5];
The compiler does not report an error.
I do not understand, what i) and ii) really mean. An explanation in simple words would be fine. Also, any assistance on iii) is welcome.
Question 1:
Read about constructors : http://www.cprogramming.com/tutorial/constructor_destructor_ordering.html
Question 2:
Read about initialization list:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
Question 3:
Read about pointers to derived class:
http://www.learncpp.com/cpp-tutorial/121-pointers-and-references-to-the-base-class-of-derived-objects/
I think this way instead of just answering your question you could understand what's going on,
I think an illustration will be best.
i)
class A
{
int i;
public:
A(int ii) : i(ii) {}
}
The part i(ii) is an example of a member - object initialiser. Since C++ guarantees all constructors of members will be called before the constructor body is entered, this is your only way of specifying which constructor to call for each member.
ii) In C++ there is no super keyword. You must specify the base class as such:
class B : public A
{
public:
B(int i) : A(i) {}
}
That's partially due to the fact C++ allows multiple inheritence.
iii) Note that you haven't created any objects, only pointers to objects. And it's by this method polymorphism via inheritence is acheived in C++.
#include <iostream>
class Base
{
public:
Base(int i)
{}
virtual ~Base() = 0
{}
protected:
int i_;
};
class Derived: public Base
{
public:
Derived(int i, int j) : Base(i), j_(j)
{}
private:
int j_;
};
int main(int argc, char* argv[])
{
//Base b(1); object of abstract class is not allowed
Derived d(1, 2); // this is fine
}
As you can see i_ is being initalized by the Derived class by calling the Base class constructor. The = 0 on the destructor assures that the Base class is pure virtual and therefore we cannot instantiate it (see comment in main).
i) The following is what is known as an initializer list, you can use initializer lists to make sure that the data members have values before the constructor is entered. So in the following example, a has value 10 before you enter the constructor.
Class baseClass
{
int a;
public:
baseClass(int x):a(x)
{
}
}
ii) This is how you would explicitly call a base class constructor from a derived class constructor.
Class derivedClass : public baseClass
{
int a;
public:
derivedClass(int x):baseClass(x)
{
}
}
iii) You can't directly create instances of an abstract class. However, you can create pointers to an abstract base class and have those pointers point to any of its concrete implementations. So if you have an abstract base class Bird and concrete implementations Parrot and Sparrow then Bird* bird could point to either a Parrot or Sparrow instance since they are both birds.