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
{ ... }
Related
When inheritance, do the variables in the base class get copied into the derived class? how the architecture of the child class would be?
{
public:
int m_id;
Base(int id=0)
: m_id(id)
{
}
int getId() const { return m_id; }
};
class Derived: public Base
{
public:
double m_cost;
Derived(double cost=0.0)
: m_cost(cost)
{
}
double getCost() const { return m_cost; }
};
does m_id get copied into derived while derived object's instantiation ?
The derived class (Derived) is not copying the base class (Base) in a strict sense. Derived is inheriting from Base therefore Base is part of Derived. Think of Derived extending Base with new methods and new members.
In your example, Base has a default constructor because the first parameter is an optional parameter (Base(int id=0), you can call the constructor without any arguments to set id to 0).
When you use inheritance, Derived must always call Base's constructor in Derived's constructor before doing anything else (to make sure Base's variables are initialized). However, because Base has a default constructor, the compiler does so magic to make this optional.
If you want to call a specific Base's constructor from Derived's constructor you can do the following:
Derived(double cost=0.0) : Base(1 /* or whatever you want it to be */)
{
m_cost = cost;
}
Lets say I have a base class with protected member:
class Base
{
public:
Base(int data)
: m_attribute(data) {}
protected:
int m_attribute;
};
and derived class from base:
class Derived : public Base
{
public:
int get_attribute()
{
return m_attribute;
}
};
First of all: I can do this, right? Is this totally legal?
If yes, then here is the question:
I can't change anything in a Base class;
I have a Base class object, and I need to access its m_attribute member;
Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function? Something like this:
Base base(5);
Derived* derived = static_cast < Derived*>(&base);
int base_attribute = derived->get_attribute();
Or what are other ways to access protected member? I know that friend function is an option, but I can't change anything in the base class
Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function?
Most definitely not. An instance of a base class is not an instance of a derived class. Your conversion is ill-formed.
Here is a valid way:
struct kludge : Base {
kludge(const Base& b): Base(b) {}
operator int() {
return m_attribute;
}
};
usage:
Base base(5);
int foo = kludge(base);
This kludge works by copy constructing the base sub object of the derived type. This of course depends on the base being copyable - which your Base is. It's easy to tweak to work with movable as well.
As a syntactic sugar, the kludge is implicitly convertible to the type of the member. If you prefer, you could use a getter.
if base class doesn't have a default constructor after overloading it to take some arguments and no default one is there then the derived classes must use member-initializer list to initialize the base part otherwise you cannot instantiate the derived class getting the compiler complaining about missing default constructor in base class:
class Base
{
public:
// Base(){} default constructor by default the compiler creates one for you unless you overload it so the next one taking one parameter will hide this one
Base(int data) // hides the default ctor so derived classes must use member-initializer list
: m_attribute(data) {}
protected:
int m_attribute;
};
class Derived : public Base
{
public:
Derived() : Base(0){} // you must use member intializer list to initialize the part Base
//Derived(int x) : Base(x){} // also ok
int get_attribute(){ return m_attribute; }
};
int main()
{
Derived dervObj;
Derived* derived = static_cast < Derived*>(&baseObj);
int base_attribute = derived->get_attribute();
cout << base_attribute << endl;
}
also you cannot cast the address of class base to derived object but cast an object of base class to derived one.
so in your example writing in main:
Derived* derived = static_cast < Derived*>(&baseObj); // is like writing:
char* cp = static_cast < char*>(&int); // you must convert a variable not a type
why you want to access protected members from outside??? keep in mind that public inheritance will copy all the members of base to derived class but private.
using friendship or making member data public will make it possible to access it from outside but it undermines the principles of data-hiding and encapsulation however friendship in some cases it's a must and there's no other alternative then use it carefully but making data public it's better to get back to structs
The Derived class can access and modify the public and protected Base class properties and methods.
Then, you can't case Base into Derived.
Derived inherit from Base, so Derived is a Base.
But a Base is not a Derived (a Car is a Vehicle, a Vehicle is not a Car).
So if you need a getter, put it directly into Base, or instanciate a Derived instead of a Base.
Firstly:
Derived* derived = static_cast < Base*>(base);
This is not valid and illegal. Won't compile. You can't static cast Base to Base*.
And to answer your question:
Base base(5);
Derived& derived = static_cast<Derived&>(base);
std::cout << derived.get_attribute();
Or if you want to use a pointer because you think you're cooler:
Base base(5);
Derived* derived = static_cast<Derived*>(&base);
std::cout << derived->get_attribute();
EDIT: static_cast doesn't have any overhead on runtime. It is static, hence it's a compile-time thing. Both methods will yield the same result.
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.
I have a question about the way classes using inheritance are constructed. In the example below, the call to the Base constructor is dependent on a function implemented in the Derived class. This function is again dependent on the Derived member generator, which will not be initialized until after the Base constructor call.
If the Base class is constructed first, won't the variable Base::in_ contain garbage data?
class Derived
: public Base
{
Derived()
: Base(get_data()),
generator(5) {}
Generator generator;
int get_data() { return generator.get_some_data(); }
};
class Base
{
Base(int in)
: in_(in) {}
int in_;
}
First, nothing in your code is polymorphic. Polymorphism is about virtual functions.
Next, your class Base depends on nothing. Look between class Base { and the matching }, there's nothing in there that depends on anything outside.
What happens is the construction of the Base subobject within Derived depends on another member of Derived, which is constructed after Base. Your analysis is basically correct, it's a real problem and it needs to be solved by refactoring your classes.
The easiest way is two-stage initialization of Base (the following is pseudocode and probably will not compile):
class Base {
Base(int in = 0) : in_(in) {}
void set(int in) { in_ = in; }
int in_;
};
class Derived : public Base {
Derived() : Base(), generator(5) {
Base::set(generator);
}
...
};
Another method is moving the dependency to another base class:
class Base2 { ... generator implemented here ... };
class Derived : public Base2, public Base {
Derived() : Base2(5), Base(Base2::generator) {}
};
See Order of calling constructors/destructors in inheritance
The constructor for Base will be called before any members of Derived are initialized. So generator will not have been initialized when get_data() is called.
Basically, Base will be initialized with garbage.
I have no idea what the standard says, but this is clearly a matter of what is the value of generator when get_data() is called, as it would be if you call it from somewhere else then the constructor.
Code called from within a constructor is no way different to other code.
My guess is that get_data() is called before generator is constructed and thus you will get a NULL exception at runtime.
Another point to mention is that the base class is of course being constructed first. It is the base class. Derived IS A Base, it has a field in_.
As a rule of thumb it is always a good pattern to:
Avoid method calls from the constructor. Use an additional init method for that.
In any case beware of circular constructor calls.
You also could make get_data abstract in Base and then call it within the Init() of Base which would IMHO be the right way to implement a dependency to child classes as you call it.
class Derived
: public Base
{
Derived()
: Base(),
generator(5) {}
Generator generator;
virtual int get_data() { return generator.get_some_data(); }
};
class Base
{
Base()
{
}
Init() {
in_ = get_data();}
int in_;
virtual int get_data() = 0;
}
#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?