Using object members before object is constructed - c++

I have following simple code:
#include <iostream>
#include <vector>
template <class Derived>
struct Base
{
Base()
{
static_cast<Derived*>(this)->foo();
}
std::vector<int> m_ints;
};
struct Derived : Base<Derived>
{
Derived() : Base()
{
std::cout << a;
}
void foo()
{
m_ints.push_back(37);
a = 4;
}
int a;
};
int main()
{
Derived d;
return 0;
}
I know about order of calling constructors when object is created. Constructor are called from the "most base -> down". So At the Base constructor Derived object is not fully constructed.
1) Is it safe, to call Derived::foo in Base constructor, when Derived::foo do no touch Derived object? I mean, when there is no such line as a = 4, just touching Base object.
2) If I run posted code, it really works, although I'm touching a which should not exist at that time. Is it guarantee to work? (I tested it on VS2013, VS2010, and GCC 4.8.1 on Ideone)

It will work in this specific case, but I would advise not to do this.
Subtle changes in the code might suddenly break the logic (e.g. someone making the method foo virtual, someone initializing data member a in the constructor or Derived, ...).
If the base class needs information from a derived class, then the derived class must pass that information to the constructor of the base class. In this class, the value 37 should be passed from the constructor of Derived to the constructor of Base.
And when data member a must be initialized, initialize it in the constructor of Derived, not somewhere else.
EDIT: In C++11, if the Derived class wants to inject code in the constructor of Base, it can pass a lambda to Base. Base then simply executes the lambda in its constructor.

Related

Reset unique_ptr for protected virtual destructor base class

I'm in a situation where in I've to create an object of either type A or B depending on a condition. Both A and B inherit from the same base class, in this case - Base. The base class has a virtual protected destructor.
The variable is declared as std::unique_ptr<Base> member and then depending on the condition, I use either std::make_unique<A> or std::make_unique<B>.
I'm calling member.reset() but getting a compiler error since the destructor is declared protected. But what I don't understand is why is the compiler not able to call the correct destructor since the destructor is also declared virtual.
But is there some other way to fix this? And why exactly does the virtual destructor not help here?
Full code -
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() = default;
protected:
virtual ~Base() = default;
private:
int a;
};
class A : public Base
{
};
class B : public Base
{
};
unique_ptr<Base> get_object(bool cond) {
if (cond) {
return make_unique<A>();
} else {
return make_unique<B>();
}
}
int main()
{
cout << "Hello World";
bool cond;
cin >> cond;
unique_ptr<Base> a_or_b = get_object(cond);
a_or_b.reset();
return 0;
}
The base class has a virtual protected destructor.
I don't see any point in that. Making the destructor protected disallows destroying objects through base class pointers. This makes sense as a protection mechanism if doing so would cause undefined behavior (i.e. if the destructor is non-virtual and the most-derived type different from the base class type).
However, making the destructor virtual intents it to be called through the base class pointer in order to destruct also possibly derived class objects, contradicting the effect of protected.
std::unique_ptr is unable to destroy the object through the base class pointer because of the reason given above. virtual does not change that calling the destructor through the base class pointer is disallowed.
See also the C++ core guidelines rule C.35.

How to declare an "unknown" derived class as base class as a member and allow the derived version of member function to be called?

I am currently trying to set a member of a class (myClass) to be some derived classes (Derived1, Derived2,...) of a Base class. Since the class don't know which derived class it is, the member type is set to Base class, it is only set to the derived class when constructed.
The derived classes all have a common member function which is implemented differently (Base class has a virtual version). However, when the this function is called from myClass, it always call the Base class version rather than the derived classes.
class Base
{
public:
Base(){}
virtual void who() { cout << "this is Base"; }
}
class Derived1 : public Base
{
public:
Derived1() : Base() {}
void who() { cout << "this is Derived1"; }
}
class myClass
{
private:
Base unknownDerived;
public:
myClass(const Base& inputDerived) { unknownDerived = inputDerived; }
void whosthere() { unknownDerived.who(); }
}
The output above is "this is Base", the Base class version is called instead.
Is there a way to include a member without specifying the actual derived class it is, but be able to call its specific function ( who() )?
thanks a lot!
When you declare Base as a member, Base is what you actually get. Even if you assign a Derived type to it, you experience what's called "slicing", where only the Base part of the derived object is copied, and your object is still a Base.
In C++, polymorphism only works through pointers and through references.
To make a real member object (not an indirection to the object) in myClass, you will need to make myClass have a template parameter, and you can decide at compile time what type it will be. Otherwise, you must use pointers and/or references.
Now you have to be clear about memory ownership, and proper cleanup. You may make the caller transfer the ownership of the object (by taking a unique_ptr) or you might insist that Base has a virtual clone() function to create a deep copy of the object. Further, you most likely will need a virtual destructor in your base class as well.

Why can't Initialize the data member of base class in the constructor initializer list of derived class?

such is the code,and with the error:"illegal member initialization: 'a' is not a base or member",what is the meaning of the error info,and why??
class A{
public:
int a;
};
class B:public A{
public:
B();
};
B::B():a(10){ // put "a(10)" into the constructor body is right
}
By the time the constructor of the derived class is invoked, the base class must already be constructed. So it's already too late. To see why it must be this way, consider:
class Base
{
public:
int i;
Base(int q) : i(q) { ; }
};
class Middle : public Base
{
public:
Middle() : Base(2) { printf("i=%d\n", i); }
};
class Derived : public Middle
{
public:
Derived() : i(3) { ; }
}
Now, think about it. The Middle constructor has to run before the Derived constructor. And the Middle constructor ensures that i is 2. So how can the Derived constructor later re-construct it with a different value?
See this answer for a more complete explanation of what's going on here. Basically, you cannot initialise A::a in the initialiser of B, because it is ill-formed according to the standard.
One more important piece of information - remember that if a class does not initialise a member object via the constructor initialization list, then the default constructor for that member will be invoked before that first statement in the base class constructor is executed. When you use the initialiser, what you are actually doing is specifying a constructor to be used INSTEAD of the default constructor.
Clearly when you are constructing a derived class, the parent class member has thus already been constructed, so you cannot reconstruct the base member again, which is what you are trying to do in this example by including it in the derived class initialisation list.
As an aside, if you all you want is to have the derived class be able to set the value of A::a to a specific value, then use the following code instead:
B::B()
{
a = 10;
}
Because the base class may want to initialize things its own way. The proper method is to call on of the base constructors in the initializer list and let the base ctor initialize itself.

Instantiate a derived class object, whose base class ctor is private

How to instantiate a derived class object, whose base class ctor is private?
Since the derived class ctor implicitly invokes the base class ctor(which is private), the compiler gives error.
Consider this example code below:
#include <iostream>
using namespace std;
class base
{
private:
base()
{
cout << "base: ctor()\n";
}
};
class derived: public base
{
public:
derived()
{
cout << "derived: ctor()\n";
}
};
int main()
{
derived d;
}
This code gives the compilation error:
accessing_private_ctor_in_base_class.cpp: In constructor
derived::derived()': accessing_private_ctor_in_base_class.cpp:9:
error:base::base()' is private
accessing_private_ctor_in_base_class.cpp:18: error: within this
context
How can i modify the code to remove the compilation error?
There are two ways:
Make the base class constructor either public or protected.
Or, make the derived class a friend of the base class. see demo
You can't inherit from a base-class whose only constructor is private.1
So make the base-class constructor public/protected, or add another base-class constructor.
1. Unless, as Nawaz points out, you are a friend of the base class.
You can't. That's usually the reason to make the only c'tor private, disallow inheritance.

protected inheritance error

#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
public:
derived(){}
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}
Why is this program giving error as In constructor derived::derived():
error: no matching function for call to base::base()
Please explain. As i have read in stackoverflow that in case of inheriting as protected, protected members of base class became protected member of derived class. If I am wrong then please share a good link to clear my misconception
Once you define a constructor for any class, the compiler does not generate the default constructor for that class.
You define the parameterized constructor(base(int i)) for base and hence the compiler does not generate the no argument constructor for base.
Resolution:
You will need to define a constructor taking no arguments for base yourself.
Add this to your base class:
base():a(0)
{
}
EDIT:
Is it needed to define default constructor to every class? Or is it necessary to have the constructor that matches the derived type also present in base type?
The answer to both is NO.
The purpose of constructors in C++ is to initialize the member variables of the class inside the constructor. As you understand the compiler generates the default constructor(constructor which takes no arguments) for every class.
But there is a catch, If you yourself define (any)constructor(one with parameters or without) for your class, the compiler does not generate the default constructor for that anymore. The compiler reasoning here is "Huh, this user writes a constrcutor for his class himself, so probably he needs to do something special in the constructor which I cannot do or understand", armed with this reasoning the compiler just does not generate the default no argument constructor anymore.
Your code above and you assume the presence of the default no argument constructor(When derived class object is created). But since you already defined one constructor for your base class the compiler has applied its reasoning and now it refuses to generate any default argument constructor for your base class. Thus the absence of the no argument constructor in the base class results in the compiler error.
You must give a value to the base constructor:
class Derived : protected base
{
public:
Derived() : base(0)
{
}
};
Depending on your implementation, give the value to the base constructor. However, you may want the Derived constructor to take also int as an argument, and then pass it to the base one.
You need to implement an empty constructor in base or invoke the defined base(int) constructor explicitly from derived c-tor. Without it, when derived c'tor is activated,
it is trying to invoke base() [empty c'tor], and it does not exist, and you get your error.
You haven't defined a default constructor for Base..
When you instantiate an instance of Derived, it will call the Derived() constructor, which will in turn try to call the Base() default constructur which doesn't exist as you haven't defined it.
You can either declare an empty constructor for base Base::Base() or call the existing one as below:
#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
derived(): Base(123) {} --this will call the Base(int i) constructor)
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}