Avoid constructor with empty base class with virtual method - c++

I have an empty base class with a virtual function. Is there any way I can avoid manually implementing the constructors of Derived in order to be able to initialize it?
struct Base
{
virtual int f(int) const = 0;
virtual ~Base() = 0;
};
Base::~Base() {}
struct Derived: public Base
{
int v;
int f(int) const override{ return v;};
};
int main()
{
return Derived{5}.f(3);
}

Is there any way I can avoid manually implementing the constructors of Derived in order to be able to initialize it?
No. Having a base class and virtual functions causes Derived not being an aggregate.
If you remove the virtual functions, you have aggregates and you can
return Derived{{}, 5}.f(3);
// ^^ explicitly initialize base class
but as this is not the point of your question, this is no solution to it.

Both the base class and the derived class has an implicit default constructor (as well as copy and move), and there is no need to manually implement those.
Neither class is an aggregate, so they cannot be initialised using list initialisation without implementing a custom constructor that accepts compatible list of arguments. This is why your example program does not work. Neither class can become an aggregate without removing the virtual member function.
So, your options are:
Don't use list initialisation, except with an empty list of parameters which is a special case that performs value initialisation which invokes the default constructor
or provide a custom constructor for the list of arguments that you want to pass
or remove the virtual member function so that the classes become aggregates, and their members can then be initialised directly with list initialisation

Related

Problem with abstract class inheritance and constructor at C++

class Base {
public:
Base(int a) : a_(a) {
//do something
someMethod();
//do something else
};
protected:
int a_;
virtual void someMethod() = 0 {};
};
class Derived : Base {
public:
Derived() {
Base::Base(42);
}
protected:
void someMethod() override {
//realisation
}
};
int main() {
Derived *obj = new Derived();
delete obj;
}
This code doesn't work by two mistakes: base class's default constructor is needed and base class's constructor with parameters can't be called because of using abstract methods
My problem is that someMethod() realised in class Derived is not called at all when I create object of class Derived. Also I don't want to use default constructor of class Base, but compiler is swearing.
How can I correct my code to see functionality that I want?
How can I correct my code to see functionality that I want?
Remove the call to a pure virtual function in the constructor of Base.
Call someMethod in the constructor of the derived class that overrides it instead.
Provide an initialiser to the Base subobject in the member initiliser list. If you don't provide an initialiser to the base, it will be default initialised.
Why this cannot work ?
This design will not work because of the way obects are constructed.
When you construct a Derived, the first thing happening is that a Base object is constructed with a Base constructor. There is no Derived object at this moment, so if you'd invoke the virtual function in the Base constructor, it would be the virtual that would be valid for the Base class until you leave the Base constructor's body.
This is allowed by the standard, but with restrictions:
[base.class.init]/16: Member functions (including virtual member functions) can be called for an object under construction. (...) However,
if these operations are performed in a ctor-initializer (or in a
function called directly or indirectly from a ctor-initializer) before
all the mem-initializers for base classes have completed, the program
has undefined behavior.
These restriction do not apply to virtual functions that are called from the constructor body, since the body is executed after all initializers.
But in your case the virtual function is pure virtual for the Base. So it's UB according to the following clause:
[class.abstract]/6: Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making
a virtual call to a pure virtual function directly or
indirectly for the object being created (or destroyed) from such a
constructor (or destructor) is undefined.
What is the alternative
There is unfortunately no other real alternative than using a two step initialization in which you first construct the object and then call an initialization function before using the object.
The only issue with this approach is the risk of forgetting the call to the initialization function. You can protect you against this:
using a flag to indicate if the intialization has taken place and check this flag in all member functions (yes, it's a little overhead).
if you have an abstract class, you may perhaps use a factory pattern (factory method or abstract factory). You could then let the factory do the call.
you may use the builder pattern, and make sure that the constructor is only visible to the builder who won't forget the initialization either.
Other problems with your code
You must be careful about how you "call" the base constructor from the derived constructor:
class Derived : Base {
public:
Derived() : Base(42) // this is the correct place !
{
//Base::Base(42); //<==== OUCH !!! NO !! This creates a temporary base object !!
}
...
};
You'd also need to be careful about the pure virtuals (I don't know if it's a typo or if your compiler could compile your code):
virtual void someMethod() = 0; // if it's abstract, no pending {} !

Can we avoid the default constructor in this case?

Observation: The constructor of ClassMain needs to call Init before it can constructor a member variable a. Since the ClassA has no default constructor, the code doesn't compile.
ClassA
{
public:
// This class has no default constructor
ClassA(...){}
};
class ClassMain
{
public:
ClassMain(...) {
Init(...);
a = ClassA(...); // error: ClassA has no default constructor
// a has to been constructed after the Init is called!
}
ClassMain(...) {
Init(...);
call other functions
a = ClassA(...);
}
private:
// initialize environment
void Init(...) {}
private:
ClassA a;
};
Question> The simple solution is to provide a default constructor for ClassA. However, I would like to know whether there is a better solution to address the issue above?
The better solution is not to require an Init function at all. You're trying to reinvent constructors, and breaking their design in the process.
If Init does too much work for a constructor, then do it outside and pass the resulting resources into ClassMain as a constructor argument; notice how you're already doing all the work in the constructor's scope anyway, thereby not gaining anything appreciable over proper initialisation.
Of course, if you must perform a ton of work before initialising a, and you cannot pass in a ClassA& from the outside and initialise from that, then you're simply going to have to have a be an indirect member.
There is one nasty workaround you could use: have Init actually be a base constructor...
The obvious solution is to call Init() from the initializer list of an early member or a base class. Once this subobject is constructed its results can be passed to the constructors of other subobjects. For example, when defining stream classes I typically privately inherit from a virtual base containing the stream buffer:
struct somebuf_base {
somebuf sbuf;
// ...
};
class somestream
: private virtual somebuf_base
, public std::ostream
{
public:
somestream(someargs)
: somebuf_base(someargs)
, std::ostream(&this->sbuf) {
}
// ...
};
Since base classes are constructed in the order they appear but virtual bases before non-virtual bases, the base class containing the sbuf member is constructed first. Its constructor replaces your Init() function.
When using C++ as of the 2011 revision, you might also use forwarding constructors to share logic between multiple constructors.
It's easier to take a pointer to ClassA; So, you can instantiate it whenever you want.(after the init())
If you used a pointer, don't forget to implement the virtual destructor and release the allocated memory for the ClassA *a
If you absolutely must call some function at the start of your constructor, and can't put that setup into some base class or early-constructed member, you could use this ugly trick:
ClassMain::ClassMain(int main_param)
: a( (Init(init_arg), class_a_arg1), class_a_arg2 )
{
}
In this case: No, we cannot avoid that.
The reason is that when calling Init or any other member function you are guaranteed by the language that the object you are in exists. As a is a member of ClassMain it must be constructed before any function in ClassMain can be called.
The only chance that you have here is to refactor the code.

design and initialization of data in derived classes

I have the following hierarchy:
Base_class
|
Traits_class
|
Concrete_class
Now the thing is that the data is contained in the Base_class (it needs to be there because the Traits_class has to have access to it. Traits_class is a class template that has different functionality depending on the template parameter passed (so I use partial template specialization for the different classes). Finally, at the lowest level, the Concrete_class is also a class template. I create instances of Concrete_class only.
Now the question is: I have written all constructors, the destructor and I have provided move semantics within the Concrete_class. That means that I do not call the base constructors, but I initialize the state directly in the derived classes.
Can someone point out if there is a problem with this? Only the destructor is declared in the Base_class, and declared as protected. Is there an evident flaw in this design?
Thanks for your insight!
EDIT
So I revised the design following Yakk's comment on the CRTP, and now I have
Traits_class
|
Concrete_class
I have also moved all data to the Concrete_class, and thanks to CRTP I can have access to it in the Traits_class. Something weird happened though, as I couldn't access the data in the Traits_class within the constructor of the Traits_class. I mean, I did access to it, but it seemed as if I was accessing ghost data, because I initialized the members in Traits_class (and even printed within the Traits_class constructor), but then just afterwards the class was empty. So I really don't understand what happened (I was const_casting the Traits_class into the Concrete_class to do this).
In the end, I wrote just static member functions in the Traits_class to initialize the members of the Concrete_class. I guess I could have used protected member functions to do the same thing (because I'm inheriting from Traits_class), but I believe it's the same thing.
If you have any further comments, please let me know. And thanks again for your C++ wisdom.
aa
There is an error in your reasoning. A constructor always initializes all base classes and nonstatic members (technically, a virtual base is initialized by the most-derived type and not by any of the other bases' constructors), so the Base_class will actually be initialized by its compiler-generated default constructor (or compiler-generated copy/move constructors if you're doing a copy or move), which will initialize all data members using their default (or copy/move) constructors. You may later assign those members in the concrete class's constructors, but initialization has already occurred by this point.
Since the base class owns all the data members, it will actually be the base class that initializes all data members when a copy or move occurs. If you write your own copy or move constructor in the most-derived class, you'll either need to invoke the base class's copy/move constructor in your initialization list or the data members will be default-constructed and you'll be forced to use a copy/move-assignment after the fact. This is often inefficient and in some cases may be incorrect. (For example, I've written classes that could be move-constructed, but could not be move-assigned because of slicing issues; if you had such a class in your Base_class as a data member, you couldn't implement move semantics solely in the Concrete_class.)
If you must initialize all the data members from Concrete_class, I recommend you provide a protected constructor in Base_class that takes all data members by value and moves them into its own data members, and provide a perfect-forwarding constructor in Traits_class (or inherit the base's constructor, if you are using a compiler with this support). This allows the concrete class to specify the values for initializing the data members, but allows the base class to do the actual initialization. It also allows the Base_class and Traits_class constructors access to the fully initialized data members (whereas otherwise they can only access the data members in their default-initialized state).
Here's an example:
struct Base_class {
protected:
Base_class( string s ) : s_( move(s) ) { }
~Base_class() = default;
// Request copy/move, since we're declaring our own (protected) destructor:
Base_class(Base_class const &) = default;
Base_class(Base_class &&) = default;
Base_class &operator=(Base_class const &) = default;
Base_class &operator=(Base_class &&) = default;
string s_;
};
template<int>
struct Traits_class : Base_class {
protected:
template<typename... P>
Traits_class( P &&p )
: Base_class( forward<P>(p)... )
{ }
};
template<int I>
struct Concrete_class : Traits_class<I> {
Concrete_class( char c )
: Traits_class<I>( string( I, c ) )
{ }
};
As a side-note, the data doesn't necessarily have to be in Base_class for Traits_class to be able to access it. You could provide access via a protected virtual function if you don't mind the overhead of a virtual function call and if you don't need access within the constructors or destructor (which I'm assuming you don't, since currently the data members don't have their final values until after Concrete_class's constructor runs). Or, to avoid the virtual call overhead, you could use the Curiously Recurring Template Pattern as #Yakk mentions.
== RESPONSE TO EDIT IN ORIGINAL QUESTION ==
The base class's constructor will run before the derived class's constructor, so if the data is stored in the derived class, it will be uninitialized in the base class's constructor (and already reclaimed in its destructor). You can think of a constructor as taking an instance of base class and turning it into an instance of derived class (by initializing the derived part of the class, etc.), and as a special case, the constructor for a class with no base classes turns "nothing" (raw storage) into an instance of the class.
So, when your traits class constructor is running, it isn't yet a concrete derived class. Consequently, accessing the derived class's data members or otherwise using the class as a derived class is illegal. The language even enforces this for virtual functions; if you call a virtual function inside a base class's constructor or destructor, it will call the base version of the function. Example:
#include <iostream>
using namespace std;
struct Base {
Base() { cout << "Base ctor\n"; v(); }
~Base() { v(); cout << "Base dtor\n"; }
protected:
virtual void v() const { cout << "Base::v\n"; }
};
struct Derived : Base {
Derived() { cout << "Derived ctor\n"; v(); }
~Derived() { v(); cout << "Derived dtor\n"; }
protected:
virtual void v() const { cout << "Derived::v\n"; }
};
int main() { Derived d; }
/* Output:
Base ctor
Base::v
Derived ctor
Derived::v
Derived::v
Derived dtor
Base::v
Base dtor
*/

order of calling constructor in inheritance

I am new to C++ programming language, i have a confusion about order of calling the constructor in inheritance. my question is even though the constructor and destructor are not inherited by derived class why the base class constructor will call when i create a derived class object.
The purpose of a constructor is to define how the data members should be initialised. Since a derived class inherits the data members from the base class, any constructor of the derived class must define not only how to initialise the data members that are specific to the derived class, but also those coming from the base class.
The natural way to do this (and required by the C++ Standard) is by calling a base class constructor. If you don't include a specific constructor call in the initialization list for your derived-class constructor, the default constructor of the base class will be used to initialise the base-class members.
struct base
{
int _i; // a data member
base():_i(0) {} // default constructor
base(int i):_i(i) {} // special constructor
};
struct derived : base
{
int _j; // a data member specific to the derived class
derived(int i, int j):_j(j) {} // user-defined constructor for the derived class
};
The example above illustrates how the derived-class constructor can initialise its member _j, but the member _i, coming from the base class, must be initialised using a base-class constructor.
The way it's written above, the default constructor base::base() will be automatically called by the compiler, i.e. _i will be initialised to 0.
But you can change that behaviour by including a call to a specific constructor:
struct derived : base
{
int _j;
derived(int i, int j):base(i),_j(j) {} // user-defined constructor for the derived class
};
The order of the constructor calls is: First constructor calls of the base class, then initializers for the derived-class specific members. This is only natural because the derived class, in a sense, is an extension of the base class, and it makes sense to regard the base-class part of the derived-class object as being there first.

Call virtual function defined in other classes in constructor of the current class

class A
{
public:
...
virtual bool Function(..) const {...}
}
class B : public A
{
public:
...
virtual bool Function(..) const {...}
}
class OtherClass
{
public:
OtherClass(A& a)
{
m_bool = a.Function(..);
}
private:
bool m_bool;
}
Assume that class A or class B are fully initialized before the construction of class OtherClass.
Question> Is there a problem regarding the calling of a virtual function in the constructor of OtherClass?
No, why should there be any problem? The instance of A passed (via reference) to the constructor of OtherClass is already fully initialized, so virtual functions on it work as expected.
The warning you heard is about calling virtual functions of the object you are constructing inside its constructor; in this case, virtual dispatch is disabled, i.e. in the constructor of each base class the virtual function version called is the one of the base class whose constructor is running.
The idea is that, inside a base class constructor, the object isn't yet become of its final type; in other words, while you are constructing an object that inherits from some base class, it starts as the "basest" type, and transitions to derived types when each derived-class constructor is run. This reflects in what versions of virtual functions the various constructors see when they are run.
You can read about it in more detail here.
Again, this does not affect any object that is passed to the constructor, since they are already fully constructed, so their "definitive type" (and thus the corresponding set of virtual functions) is already completely established.
If the functions are defined and not pure virtual functions or abstract base classes, the function call should be fine. the a object will call its virtual function as expected, so to answer your question, no.
Calling virtual function of A/B has nothing to do with whether it's called from OtherClass's constructor or anywhere else. So no issue.