1 Where does it say about hidden copy constructor in the base class?
It's not hidden as much as it is implicit.
Using n3290
:
§ 12 Special member functions
1/ The default constructor (12.1), copy constructor and copy assignment operator (12.8), move constructor and move assignment operator (12.8), and destructor (12.4) are special member functions. [ Note: The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them. The implementation will implicitly define them if they are odr-used (3.2). See 12.1, 12.4 and 12.8. —end note ]
So, let us follow the pointer:
§ 12.8 Copying and moving class objects
7/ If the class definition does not explicitly declare a copy constructor, one is declared implicitly. [...]
8/ The implicitly-declared copy constructor for a class X will have the form
X::X(const X&)
if
— each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B&
or const volatile B&
, and
— for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M&
or const volatile M&
.
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
And there you have it. In your case, there is a copy constructor A::A(A const&)
implicitly defined for you.
2 Where does it say about this behaviour?
Unsuprisingly, in the part devoted to exception handling.
§ 15.3 Handling an exception
3/ A handler is a match for an exception object of type E if
[...]
— the handler is of type cv T
or cv T&
and T
is an unambiguous public base class of E
, or
[...]
It is very similar to parameter passing in functions. Because B
publicly inherits from A
, an instance of B
can be passed as a A const&
. Since a copy constructor is not explicit (hum...), B
is convertible into a A
, and therefore, as for functions, a B
can be passed where a A
(no reference) is expected.
The Standard goes on:
4/ The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.
Which is really what this warning is all about.