Copy constructor is not inherited
Because the standard says so. [class.inhctor]/p3, 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.
C++ Default constructor not inherited with using when move and copy constructors present
Before C++17, the default constructor of the base class won't be inherited via using
:
All candidate inherited constructors that aren't the default constructor or the copy/move constructor and whose signatures do not match user-defined constructors in the derived class, are implicitly declared in the derived class. (until C++17)
After C++17 the code works fine.
Before that, the default constructor won't be inherited from the base class, and won't be generated for class B
because copy/move constructor are provided.
If no user-declared constructors of any kind are provided for a class type (struct, class, or union), the compiler will always declare a default constructor as an inline public member of its class.
That's why if you comment copy/move constructor out it compiles. You can add the definition explicitly as a pre-C++17 workaround. e.g.
class B : public A {
public:
B(const B&) = default;
B( B&&) = default;
B() = default;
};
The code compiles with gcc8.
Inheritance of copy constructors in C++17
[over.match.funcs]/8:
A constructor inherited from class type
C
([class.inhctor.init]) that has a first parameter of type “reference to cv1P
” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2D
if the argument list has exactly one argument andC
is reference-related toP
andP
is reference-related toD
.
See CWG2356.
C++, inherited copy ctors does not work?
Copy and move consturctors (and the default constructor) are never inherited, simply because the standard says so. All other constructors are.
That comment on cppreference was misleading(1). The same comment in the standard says:
The candidate set of inherited constructors in
D1
forB1
is
(Emphasis mine).
The standard then goes on to say that only the D1(int)
constructor is actually inherited. The copy and move constructors for D1
are implicitly-declared as for any other class, not inherited.
Refer to C++14 12.9 [class.inhctor] for details.
(1) I submitted a change to cppreference to hopefully clarify this.
What's not inherited to a C++ Derived class? Apparently, operator= and some constructors are actually inherited
Dervied has no constructors, in this case a default constructor is generated which calls the default constructor of all base classes and members.
Similar things happen with the copy constructor and assignment operator. The Base class versions are being called by automatically generated Derived class versions.
This has nothing to do with inheritance of constructors or assignment operators.
Constructor, destructor, overloaded =operator function, copy constructor do not get inherited. What this exactly means?
What that statement is trying to say, is that class B
does not automatically get a constructor B::B(int)
when you add A::A(int)
. Similarly, B::operator=(int)
is not automatically generated when you have A::operator=(int)
.
The copy constructor B::B(B const&)
can be automatically generated, in which case it expects A::A(A const&)
. But you see from the argument that it's generated, not inherited as B::B(A const&)
.
The destructor works the same - generated, not inherited - but that's less visible because there's no parameter.
why copy constructor and overloaded=operator of derived class not calling respective base class's copy constructor and overload=operator
Let us Analyze the 3 statements in the main program one by one.
We will discuss the second statement in the main program last, as that is the one that will require the maximum explanation
Statement-1: der d1, d2
This works as expected and first, the base class is constructed and then the derived class is constructed for both the objects.
Statement-3: der d3 = d1
Here we are trying to copy construct a der class object d3 from another der class object d1.
But before the derived class object can be constructed, first the base class object needs to be created.
There are 2 constructors in the base class, one is the default constructor and another is the copy constructor, how will the compiler choose which one to pick?
The answer is that we will need to tell the compiler as to which base class constructor to pick, and the way to tell this is by using the initialization list of the derived class constructor, and specifically calling the base class constructor you wish to be used.
der::der(const der &d):base(d)
{
std::cout<<"derived copy ctor\n";
x=d.x;
y=d.y;
}
In the code above, we are specifying how to construct the base class. The d reference will be upcast to base class reference for the call to base class copy constructor.
In your original version, the compiler will need a default base class constructor of the base, and which was exactly being called, as it was not specified as to how to construct the base class.
Statement-2: d2 = d1;
In this statement, you are calling the assignment operator, which is defined as here
der der::operator=(const der &d)
{
std::cout<<"derived overloaded operator\n";
x=d.x;
y=d.y;
return *this;
}
Overloaded operators are nothing but functions, and a derived class function will not automatically call the base class function.
If you need that base class version also be called then you will need to add the base class version of the call also in the function, to something like below
der der::operator=(const der &d)
{
base::operator=(d);
std::cout<<"derived overloaded operator\n";
x=d.x;
y=d.y;
return *this;
}
Once you make this change, now the base class operator= will also be called.
However, if you now examine the output of the program it will confuse you even more.
The output that this statement will now produce will be like below
base overloaded=operator
base copy ctor
base dctor
derived overloaded operator
base ctor- 0 arg
derived copy ctor
derived dctor
base dctor
Why are these constructors and destructors being called?
This is happening because the operator= function returns by value, which is not the right thing to do for the assignment operator.
In the modified version of the derived class operator, we call base class operator base::operator=(d);
This statement will call the below base class operator function
base base::operator=(const base &b)
{
std::cout<<"base overloaded=operator\n";
p=b.p;
q=b.q;
return *this;
}
However, this function returns by value, which will cause a temporary object of the base class to be created, which will then also be destructed immediately.
After this, the derived class operator also returns by value, which will require a der class to be constructed, which will, in turn, require a base class to be constructed, and this will then also be destroyed immediately.
Causing the messages which we see.
The right way to return from operator= will be returning the reference.
Hence modify the base class and derived class operators to as below
And also make the corresponding changes in the .h file.
base& base::operator=(const base &b)
{
std::cout<<"base overloaded=operator\n";
p=b.p;
q=b.q;
return *this;
}
der& der::operator=(const der &d)
{
base::operator=(d);
std::cout<<"derived overloaded operator\n";
x=d.x;
y=d.y;
return *this;
}
Once you modify the operator functions to as above the second statement will print as below.
base overloaded=operator
derived overloaded operator
Why are copy constructors of base classes not implicitly called?
Why are copy constructors different from normal constructors in this regard?
They aren't. When you do not call a base class constructor, the default constructor is called for you. This happens for every contructor.
Related Topics
Why Doesn't My Template Accept an Initializer List
Exit() Call Inside a Function Which Should Return a Reference
Why Not Use Pointers for Everything in C++
How Does the Standard Library Implement Std::Swap
How to Set the Stacksize with C++11 Std::Thread
How to Declare Constexpr Extern
Does a Declaration Using "Auto" Match an Extern Declaration That Uses a Concrete Type Specifier
C++ New Operator Thread Safety in Linux and Gcc 4
What Is the Precision of Long Double in C++
C++ Return Value Created Before or After Auto Var Destruction
Why Stdfax.H Should Be the First Include on Mfc Applications
How to Append an Int to a String in C++
Is There a Good Python Library That Can Parse C++
How to Create a Pause/Wait Function Using Qt
What Is Copy Elision and How Does It Optimize the Copy-And-Swap Idiom