I was learning about inheritance in C++. So whenever a object of a class is created a constructor is called.
And constructor is used to initialize the class variables.
#include<bits/stdc++.h>
using namespace std;
class Base
{
protected:
int x;
public:
Base(int a): x(a)
{
cout<<"Base"<<endl;
}
};
class Derived: public Base
{
private:
int y;
public:
Derived(int b):y(b)
{
cout<<"Derived"<<endl;
}
void print()
{
cout<<x<<" "<<y<<endl;
}
};
int main()
{
Derived d(20);
d.print();
return 0;
}
Since here I am creating object of base class and calling print function on this. So I should get output.
But my code is giving compiler error, why?
Can anyone help me understanding this?
When you construct your Derived object in the Derived(int b): y(b) {}, the Base part of this object has to be constructed too. Since you do provide a constructor for Base which takes an int there won't be an implicitly defined default constructor in the Base (even if it was, the int data member x would have an undefined value). Thus, there's no way to construct the d in the Derived d(20) using your definitions for both classes.
You may look toward the following approach:
// Inside Base class:
// We provide a default constructor
// As well as one that takes an int
Base(int a = 0): x(a) {}
// Inside Derived class:
// We supply a value for the Base and a value for the Derived part
Derived(int b, int d): Base(b), y(d) {}
// Inside main():
Derived d(20, 30);
d.print();
// Prints: 20 30
When we have a default constructor provided for the Base, we can even do like so, and it will compile:
// Base part will be default constructed
Derived(int b): y(b) {}
// ...Prints: 0 20
Here, the Base part of a Derived instance will have a default value, while the Derived part will have a value explicitly supplied to it. In general, this would probably be a mistake, of logical nature. Nevertheless, it will compile.
Related
I have a base_class which has no default constructor, and I'd like to define a vector version of it (called derived_class). I know I should initialize the base_class constructor in my derived_class constructor, but the code below which attempts to initialize a vector with size dim and base_class(0,1) in each row cannot be compiled (it complains error: constructor for 'derived_class' must explicitly initialize the base class 'base_class' which does not have a default constructor), unless I add a default constructor (the commented line) to base_class. Do I miss or misunderstand something? Is there a way to make it work without defining the default base_class constructor?
#include <iostream>
#include <vector>
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class : public base_class
{
public:
derived_class(int dim): vector_object(dim, base_class(0,1)){};
std::vector<base_class> print_vector_object() {return vector_object;}
private:
std::vector<base_class> vector_object;
};
int main()
{
int dim = 3;
derived_class abc(3);
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
UPDATE: I understand that I can totally avoid inheritance here in this simple case, but please assume that I do need inheritance for actual practice, thanks.
UPDATE2: As hinted by #vishal, if the constructor of derived_class is written as
derived_class(int dim) : base_class(0,0), vector_object(dim, base_class(0,1)) {};
The code can pass compiler. But I still don't understand why I have to initialize in this way...
Well, since you do not want to create default constructor in base class, you can call base constructor by:
derived_class(double a, double b, int dim) : base_class(a,b), vector_object(dim, base_class(0,1)) {};
Your vector_object is a red herring and has nothing to do with the problem, as you can verify with the following piece of code which will also make the compiler complain about the missing base_class default constructor:
class derived_class : public base_class
{
public:
derived_class(int dim) {} // error, tries to use `base_class` default constructor,
// but there is none...
};
You must either provide a default constructor or use a non-default one. In every instance of derived_class, there is a base_class sub-object, and the sub-object has to be created somehow.
One possible source of misunderstanding is the fact that objects in an inheritance hierarchy are initialized from top to bottom (base to derived). It may not seem logical at first sight, but by the time the derived_class constructor runs, the base_class sub-object must already exist. If the compiler cannot provide for this, then you get an error.
So even though the derived_class constructor specifies how the base_class sub-object is created, the actual creation of the sub-object happens before the creation of the derived_class part.
You are asking the following:
shouldn't the base_class object be initialized in my code?
Your code must initialize it, but it does not. You don't initialize it anywhere, and the default initialization does not work because the base class does not have a default constructor.
Sometimes, it helps to consider inheritance a special form of composition (there are indeed some striking similarities). The following piece of code suffers from the same problem as the one in your posting:
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class // <--- no inheritance
{
public:
base_class my_base; // <--- member variable
derived_class(int dim) {};
};
Would you still think that derived_class initializes the base_class object?
Another possible source of misunderstanding is the aforementioned red herring. You are saying:
I just don't understand why I cannot initialize it in a vector (...).
Because the vector member variable has nothing to do with the base_class sub-object, or with the public base_class member variable in my other example. There is no magical relationship between a vector member variable and anything else.
Taking your original piece of code again, a complete derived_class object can be pictured as follows in memory:
+-------------------+
| +---------------+ |
| | double | | <--- `base_class` sub-object
| | double | |
| +---------------+ |
+-------------------+ +--------+--------+--------+....
| std::vector ---------------> | double | double | double |
+-------------------+ | double | double | double |
+--------+--------+--------+....
^
|
|
a lot of other
`base_class` objects
The base_class objects managed by the vector are completely unrelated to the base_class sub-object that owes its existence to class inheritance.
(The diagram is a little over-simplified, because a std::vector normally also stores some internal book-keeping data, but that's irrelevant to this discussion.)
However, your code does not make a convincing case for inheritance anyway. So why do you inherit in the first place? You may as well do like this:
#include <iostream>
#include <vector>
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class // <--- no more inheritance (and thus wrong class name)
{
public:
derived_class(int dim) : vector_object(dim, base_class(0,1)){};
std::vector<base_class> print_vector_object() {return vector_object;}
private:
std::vector<base_class> vector_object;
};
int main()
{
int dim = 3;
derived_class abc(3);
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
Are you sure, that a derived_class-object is a base_class-object and holds a vector of base_class-objects?
I assume, you actually only want a vector of base_class-objects. If that is true, don't derive derived_class from base_class. Actually that is where your compiler message comes from. It tells you, that you'll have to initialize the base_class aspect of your derived_class-object.
So here is my solution for you (beware, code is untested and will probably contain some bugs):
#include <iostream>
#include <vector>
class base_class
{
public:
// c++11 allows you to explicitly delete the default constructor.
base_class() = delete;
base_class(double a, double b):
a_{a}, b_{b} // <- prefer initializers over constructor body
{};
private:
double a_;
double b_;
};
class derived_class // <- this name is wrong now of course; change it.
{
public:
derived_class(int dim):
// better initialize doubles with float syntax, not int.
vector_object{dim, base_class{0.0, 1.0}}
{};
// Note: this will copy the whole vector on return.
// are you sure, that is what you really want?
auto print_vector_object() -> std::vector<base_class> {
return vector_object;
};
private:
std::vector<base_class> vector_object;
};
int main(int, char**)
{
// int dim = 3; <- this is useless, you never use dim.
auto abc = derived_class{3};
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
Note: my code is meant to be C++11.
I have rewritten your class slightly
#include <iostream>
#include <vector>
class base_class {
private:
double a_, b_;
public:
//base_class(){};
base_class(double a, double b ) : a_(a), b_(b) {}
virtual ~base_class();
};
class derived_class : public base_class {
private:
std::vector<base_class> vector_object;
public:
explicit derived_class( int dim ) : base_class( 0, 1 ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
~derived_class();
std::vector<base_class> get_vector_object() const { return vector_object; }
};
int main() {
int dim = 3;
derived_class abc(3);
std::cout << abc.get_vector_object().size() << std::endl;
return 0;
}
This builds and compiles correctly. There were a few changes I made: I used the constructors member initializer list where applicable, I've added a virtual destructor to your base class; any time you inherit from a base class should have a virtual destructor, I moved all private member variables to the top of the class instead of at the bottom, I prefixed the derived_class constructor with the explicit keyword since you only have 1 parameter passed into it, I've changed the derived_class constructor to use the base_class constructor within its member's initialization list and I populated its member variable vector within the constructor using the push_back() method and statically casting the dereferenced this pointer to a base_class type, and I've also changed your print_vector_object method to just get_vector_object since it doesn't print anything and only return the member vector from the class. I also declared this method as const so that it doesn't change the class since you are only retrieving it. The only question that I have is what does the int parameter in the derived_class do? It is not used in any place and you have no member variable to store it.
This section of your derived class here
public:
derived_class(int dim): vector_object(dim, base_class(0,1)){};
where you declare your constructor is not making any sense to me.
It appears that you are trying to use the member initialization list to populate your vector member variable by passing in your derived class's passed in parameter and calling the constructor to your base class with values of {0,1}. This will not work as you would expect. You first have to construct your Base Class object which is a sub object to this derived class than within your constructor's function scope you can then populate your member vector.
What you have will cause a problem because you do not have a default constructor supplied that is available to try and construct your derived type. Since from what I can gather on what you have shown and what it appears what you are trying to do it seems that you want to have the base_class initialized to {0,1} when the derived constructor is called; if this is the case you can just call your implemented constructor for the base_class with {0,1} passed in its constructor while your derived type tries to be constructed. This will allow the derived_class to be constructed properly since the base_class has been constructed. Now that you are able to begin construction of your derived type it looks like you want to save the constructed base_class into your derived types vector member variable. This is why I do this within the constructor and not within the initialization list and I push_back an instance of the derived type that is statically casted back to a base type using the dereferenced this pointer. Also when I set a break point in the main function where you are trying to print its size and I look at derived_class's member variable it is populated with 1 object that has the values of a = 0 and b = 1. To be able to print these you would have to add public get methods to return each variable. Also if the int parameter in your derived class is not needed you can remove it along with the explicit keyword. You could also implement a second constructor for the derived type that takes in two doubles just as the base does and pass those parameters from the derived_class constructor to the base_class constructor like this:
public:
derived_class( double a, double b ) : base_class( a, b ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
I will demonstrate a simple example of a base and two derived classes where the first instance will have to set the values upon construction while the second will have to use its own constructor where there is no default constructor that is defined in the base class.
class Base {
private:
double x_, y_, z_;
public:
Base( double x, double y, double z );
virtual ~Base();
};
Base::Base() :
x_( x ), y_( x ), z_( z ) {
}
Base::~Base() {
}
class DerivedA : public Base {
private:
int value_;
public:
explicit DerivedA( int value );
~DerivedA();
};
// In This Case A Must Set The Values In The Constructor Itself: I'll Just
// Set Them To (0, 0, 0) To Keep It Simple
DerivedA::DerivedA( int value ) :
Base( 0, 0, 0 ),
value_( value ) {
}
DerivedA::~DerivedA() {
}
class DerivedB : public Base {
private:
int value_;
public:
DerivedB( int value, double x, double y, double z );
~DerivedB();
};
// In This Case B Doesn't Have To Know What Is Needed To Construct Base
// Since Its Constructor Expects Values From Its Caller And They Can
// Be Passed Off To The Base Class Constructor
DerivedB::DerivedB( int value, double x, double y, double z ) :
Base( x, y, z ),
value_( value ) {
}
DerivedB::~DerivedB() {
}
Let me know if this helps you out!
I'm having trouble with constructors in derived classes. Lets say I have the simple code below here with one base class Base and two classes whom inherits from Base, Derived1 and Derived2.
I want Derived2 to hold a pointer to Base, which could point either to Base or Derived1. I cannot manage to write the constructor for this tho. If I pass in a Derived1 object I get a empty Base once inside the constructor.
Class Base
{
public:
Base(int a): m_a(a)
{
}
protected:
int m_a;
};
//First derived class of base
class Derived1 : public Base
{
public:
Derived1(double c): m_c(c)
{
}
private:
double m_c;
};
//Second derived class of Base
class Derived2 : public Base
{
public:
Derived2(Base b, int k): m_b(&b), m_k(k)
{
}
private:
int m_k;
Base* m_b;
};
int main()
{
Base b(2);
Derived1 d1(3.0);
Derived2 d2(d1, 3);
Derived2 d3(b, 4);
}
You likely want to accept a Base* in your constructor, rather than an actual Base instance:
Derived2(Base* b, int k) : m_b(b), m_k(k)
{
}
Then you can pass the address-of the instance that you want your Derived2 instance to point to:
Derived2 d2(&d1, 3);
Derived2 d3(&b, 4);
Note that you should give them thought to the ownership of the Base object being pointed to in the Derived2 instances. Additionally, if the Derived2 object persists after the passed Base object has been deleted, accessing m_b will result in undefined behavior. If you can use C++11, consider passing and storing std::shared_ptr<Base> instead of a raw pointer.
There are many problems here. Let's ignore the design problems with Derived2 for now (naked pointers are evil).
Focussing on Derived1...
Derived1 is derived from Base, which means it is a Base. Base has only a 1-argument constructor (and therefore no default constructor)
Derived1 has a 1-argument constructor also, but this argument is initialising Derived1's data (m_c).
Since Derived is a Base, the Base part of it must be constructed at construction time. Since you must construct Base, and base has only a 1-argument constructor, you must specifically mention this in the constructor of Derived1.
Like this:
class Derived1 : public Base
{
public:
Derived1(double c, int some_value_for_base)
: Base(some_value_for_base)
, m_c(c)
{
}
...
};
I understand that you want Derived2 to hold a pointer to another Base object.
First issue: your constructor uses a value argument for the base object:
Derived2(Base b, int k): m_b(&b), m_k(k)
This means that when it gets called, a temporary copy of the parameter passed for b is made, and you will store the address of this temporary object. Of course, once you leave the statement calling the constructor, this address gets invalid. Segfault guaranteed sooner or later !
Solution: pass argument by reference (rest of code unchanged):
Derived2(Base& b, int k): m_b(&b), m_k(k)
Second issue: Your code doesn't compile, because Base doesn't have default constructor and the constructor for Derived1 and Derived2 do not provide for a valid Base in their initialisation list.
Solution 1: Either provide an explicit base intialisation in ALL derived constructors. For example :
Derived2(Base& b, int k) : m_b(&b), m_k(k), Base(k) // is k the right value ?
{ ... }
Solution 2: Or consider using a default value for the parameter of Base constructor:
Base(int a=0): m_a(a) // default parameter is 0
{ ... }
I have a two simple classes below, one base and another deriving from it.
In the derived class there are two constructor, one which takes all arguments needed for base and derived, and another which takes a Base class reference itself as argument.
I know the constructor which takes the base class reference as argument is not a good practice.
However, I was wondering why is it not considered a good practice?
It achieves the same thing as the other constructor.
Could someone please clarify why is it not a good OOP practice?
class Base
{
public:
Base(int a, int b):
m_a(a),
m_b(b)
{}
Base(const Base& b):
m_a(b.m_a),
m_b(b.m_b)
{}
~Base() {}
protected:
int m_a;
int m_b;
};
class Derived : public Base
{
public:
// Constructor which takes base class argument and initializes base
Derived(Base &base, int c):
Base(base),
m_c(c)
{}
Derived(int a, int b, int c):
Base(a, b),
m_c(c)
{}
~Derived() {}
private:
int m_c;
};
int main()
{
Base base(1,2);
Derived derived1(base, 3); //
Derived derived2(1,2, 3);
}
It would be necessary to know the context in which you specify the first Derived constructor.
However, maybe it would be more elegant to define it with the const Base parameter. Something like:
Derived(const Base &base, int c):
Base(base),
m_c(c)
{}
Thus, it tells the compiler that protects the state of base object.
Also, if you are using c ++ - 11, then you might be interested in declaring:
using Base::Base;
inside the Derived class, what makes that Derived inherits the constructors of Base. Thus, you could add in your main():
Derived derived3(1,2);
and that would compile perfectly.
In c++-11 you could you also could set a default value for m_c data member. for example
int m_c = 0;
And so the constructor inherited from Base would leave Derived in a consistent state
I believe the code you show is not bad OOP practice. Users of Derived know about, and have access to, Base by virtue of the fact that Derived uses public inheritance. Because of this, you are not adding any dependencies and so are not making anything more restrictive or complex.
That said, even if Derived was using protected or private inheritance, it might not necessarily be bad practice depending on whether users of Derived would otherwise know about class Base.
Imagine this:
class Derived { // no inheritance
public:
void doSomething(const X& b); // `X` could be `Base`, `Foo`, or `std::string` for that matter...
};
Would you call the above bad practice? I think not. The key here, as in the code you presented (assuming you added the const qualifier to the Base& as lrleon suggested,) is that you are using Base as a value type. Derived is not holding a pointer/reference to the base object being passed in, so what you have is normal parameter passing, and there is nothing unusual or bad practice about parameter passing.
#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.