inheriting default constructor, a contradiction? - c++

In C++ (inheritance subject) I read:
A derived class automatically has a default constructor, a copy
constructor, and an assignment operator, like any other class. The
compiler-generated default constructor calls the base class default
constructor
But on the other hand:
The base class constructors are not inherited We must explicitly
define any constructors the derived class needs
1) what does it mean to inherit a constructor?
2) isn't what is written above a contradiction?
I hope to add some examples if possible to help me understand.

"The base class constructors are not inherited" means that any constructor defined in a class Base is not available for a derived class Derived unless it is re-defined in Derived. This is also valid for the default constructor. But, "A derived class automatically has a default constructor" says that the compiler will automatically generate a default constructor, just as it does for every class. So the compiler will re-define a default constructor in a derived class; it is still not inherited.
The only thing is that "We must explicitly define any constructors the derived class needs", if there is no context under which this statement shall hold, seems wrong. There are definitely constructors available in a derived class that have not been defined explicitely. This can be shown easily by defining a derived class without any explicit constructor:
struct Base {
Base () { std::cout << "in default constructor of Base; not inherited, but still called." << std::endl; };
};
struct Derived : public Base {
// no explicitly defined constructor...
};
int main() {
Derived d;
}
Output:
in default constructor of Base; not inherited, but still called.
So I'd tend to say that the statement "... We must explicitly define any constructors the derived class needs" you cited is either not precise, not shown in full context, or wrong.

struct s {
s() : s_str("my string") {}; // default constructor
std::string s_str;
};
struct d : s {
std::string d_str;
};
If d didn't have any members that needed construction, the default constructor would simply construct s with s::s() which superficially looks like inheritance (and could be implemented that way). But when you add data members to the derived class, that won't work.
The default constructor for s constructs s_str with the text "my string".
If s::s() was inherited in d it wouldn't know about d_str, so wouldn't construct it. So it's not inherited.
Instead, the compiler generates a default constructor for d that constructs d_str with the default constructor for std::string and constructs the s base with s::s().

Related

Caveat with C++11 inherited constructor

https://en.wikipedia.org/wiki/C++11#Object_construction_improvement
For base-class constructors, C++11 allows a class to specify that base
class constructors will be inherited. Thus, the C++11 compiler will
generate code to perform the inheritance and the forwarding of the
derived class to the base class. This is an all-or-nothing feature:
either all of that base class's constructors are forwarded or none of
them are. Also, restrictions exist for multiple inheritance, such that
class constructors cannot be inherited from two classes that use
constructors with the same signature. Nor can a constructor in the
derived class exist that matches a signature in the inherited base
class.
Can someone give me an example to illustrate the issue with "Nor can a constructor in the derived class exist that matches a signature in the inherited base class."?
It means that if you have constructor in the derived class whose parameter list matches the parameter list of any constructor in the base class, then that derived class' constructor is taken and hides the base class'
E.g.
struct Foo
{
Foo(){std::cout << "Foo default ctor\n";}
Foo(int){std::cout << "Foo(int)\n";}
};
struct Bar : Foo
{
using Foo::Foo;
Bar(int){std::cout << "Bar\n";} // won't implicitly call Foo(int)
};
int main()
{
Bar b(1);
}
From ยง12.9/3 [class.inhctor] (Emphasis mine):
For each non-template constructor in the candidate set of inherited constructors other than a constructor
having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly
declared with the same constructor characteristics unless there is a user-declared constructor with the same
signature in the complete class where the using-declaration appears or the constructor would be a default,
copy, or move constructor for that class.

Constructor inheritance problems c

If my base class's constructor takes parameters, how do I create a class that inherits from it, and executes the base class's constructor using the derived class's constructor?
For example, assuming my base class's instructor takes an integer, and does a cool trick with it, how would I make it so all classes that inherit from it can do the same
Pseudo-code
baseClass instance(99); //does an awesome trick, nice
derivedClass instance(99); //<-- should do the same as above
As I have it now, I have my base class's constructor defined, but for the derived class, I left its constructor blank, since I want it to do exactly what the base constructor does, and nothing more. But, this gave me an error along the lines of: no matching function call to the 'baseClass()', candidates are: baseClass(int), candidate expects 1 argument, 0 provided
Do I have to make the base class's constructor virtual or something?
This is easy in the current C++ standard, but it still requires some action on your part:
struct baseClass
{
explicit baseClass(int);
};
struct derivedClass : baseClass
{
using baseClass::baseClass; // inherit *all* of baseClass' constructors
};
In the previous standard, C++03, you have to implement the constructor in the derived type and call the base class's one in the initialization list:
struct derivedClass : baseClass
{
explicit derivedClass(int i) : baseClass(i) {}
};
Note: I use struct here to save typing: default member access and inheritance is public.
The idea is that derivedClass will need to call baseClass constructor anyway, since it needs to to complete its construction. The error you get is due to the fact that, without calling a the base constructor explicitly, the compiler is trying to call the default one.
However, in your case, it does not exist, since you already defined a constructor that takes an int. To do what you want, a solution could be to do this:
class derivedClass : baseClass {
public:
derivedClass(int x) : baseClass(x) {}
};

Copy constructor - is the base one called before the derived one?

I don't understand how the copy order works within a class hierarchy
This code:
class Base
{
protected:
void myBaseMethod()
{
cout << "basemethod";
}
Base() { cout << "default constructor - base"; }
~Base() { }
Base(Base& other)
{
cout << "copy constructor - base";
}
Base& operator= (Base const &)
{
cout << "assignment operator - base";
}
};
class Derived : private Base
{
public:
Derived()
{
cout << "default constructor - derived";
}
};
int main()
{
Derived eaObj;
Derived efu = eaObj;
return 0;
}
outputs "default constructor - base" "default constructor - derived" as expected then it outputs "copy constructor - base".
Which copy constructors are called when I copy an object? First the base class ones then the derived class ones? What if they're virtual?
The copy constructor called is that of the static type of the
object, in your case, Derived. The compiler generated copy
constructor calls the copy constructors of each of the bases,
and since you didn't provide a copy constructor for Derived,
this is what happens in your case.
If you define the copy constructor, you need to explicitly
call that of the base; otherwise, the default constructor of the
base will be called. (In a few rare cases, this is what is
wanted. But not usually.)
If the inheritance is virtual, constructors for the virtual
bases are called from the most derived class. Copy constructors
work like any other constructor here: if the most derived class
has a compiler generated copy constructor, it will call the copy
constructor of each of the virtual bases; if it has a user
defined copy constructor, it's up to the programmer to call the
copy constructors of the bases. (In my experience, it's rare
for virtual bases to contain data members, so the copy
constructor and the default constructor both do the same thing.)
Which copy constructors are called when I copy an object? First the base class ones then the derived class ones? What if they're virtual?
In your case, the copy-ctor of Derived is called, since you are copying a Derived object. However, since you did not define that copy-ctor, the compiler generates one for you. That generated copy-ctor copies all parts of the Derived object, including its Base subobject. That is where you get the output from.
The constructors are not calle after another. The Base constructor is called inside the Derived constructor, in the initialization list, before Derived's constructor body is entered. This applies for all constructors, not only for copy-ctors. If you have not mentioned the Base part in a Derived constructor's init list, Bases default constructor gets called implicitly by the compiler.
Wrt virtual constructors: there are no virtual constructors in C++.

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.