Implementation supplied copy constructor and assignment operator
I have a small confusion regarding the situations where the implementation (compiler) will not supply the copy constructor and the copy assignment operator.
- When we declare the copy ctor and/or copy assignment operator in our class.
- Some says when we derive from a class which has a private copy ctor and/or copy assignment operator.
I am a little confused about the second situation, is the second situation is precisely.
a) The implementation will not declare them for you, so you will get a compile time error. OR b) The implementation will declare and define them, but when the compiler defined implementation tries to find the base class' method, we will get a compile time error.I had an interview yesterday, I said its (b) that is happening but the interviewer disagrees, he says its (a).
I tried to compile the following code in both Microsoft C/C++ 14.00 and gcc 4.4.5
struct A
{
private:
A& operator = ( const A& );
};
struct B : A
{
};
int main()
{
B b1;
B b2;
b1 = b2;
return 0;
}
Microsoft compiler output
ctor01.cpp(9) : error C2248: 'A::operator =' : cannot access pr开发者_JS百科ivate member declared in class 'A'
ctor01.cpp(4) : see declaration of 'A::operator ='
ctor01.cpp(2) : see declaration of 'A'
This diagnostic occurred in the compiler generated function 'B &B::operator =(const B &)'
gcc compiler output
Ctor01.cpp: In member function ‘B& B::operator=(const B&)’:
Ctor01.cpp:4: error: ‘A& A::operator=(const A&)’ is private
Ctor01.cpp:8: error: within this context
Ctor01.cpp: In function ‘int main()’:
Ctor01.cpp:15: note: synthesized method ‘B& B::operator=(const B&)’ first required here
So I think, the implementation will declare and define it, but when the compiler defined implementation tries to find the base class method, we will get a compile time error. Correct me if I am wrong.
Regarding the copy constructor, this is what the standard says (12.8/7) :
A program is illformed if the class for which a copy constructor is implicitly defined has:
- a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
- a base class with an inaccessible or ambiguous copy constructor.
Regarding the copy assignment operator (12.8/12) :
A program is illformed if the class for which a copy assignment operator is implicitly defined has:
- a nonstatic data member of const type, or
- a nonstatic data member of reference type, or
- a nonstatic data member of class type (or array thereof) with an inaccessible copy assignment operator, or
- a base class with an inaccessible copy assignment operator.
How the compiler reports the error, or how it actually falls into it, is pretty much irrelevant from my point of view.
However, I do believe that answer (b) is probably more correct : the base class copy assignment is declared, and it's inaccessible. The derived class has an implicitly declared copy assignment which the compiler will try to define if used, thus making the program ill-formed.
A class will have a copy constructor and a copy assignment operator implicitly declared if there is no user declared version of either. This always happens.
Simplistically, the implementation will implicitly define these only if they are actually used. If, when the implementation tries to define them, the implicit definition would be ill-formed (e.g. for copy-assignment the class contains a reference member or const member or for the copy constructor a base or member has private copy constructor) then the program is ill-formed.
A program can still be valid if it contains classes which have implicitly declared copy constructors and copy assignment operators which cannot be implicitly defined so long as it does not cause these to actually be defined by using them or causing them to be used.
Your case (b) is more accurate.
C++03 Standard 12.8p10
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.
And 12.8p12
An implicitly-declared copy assignment operator is implicitly defined when an object of its class type is assigned a value of its class type or a value of a class type derived from its class type. A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:
- a nonstatic data member of
const
type, or - a nonstatic data member of reference type, or
- a nonstatic data member of class type (or array thereof) with inaccessible copy assignment operator, or
- a base class with an inaccessible copy assignment operator.
The corresponding requirements for implicitly defined copy constructors, default constructors, and destructors have similar wordings.
Specifying that the methods exist even though their definitions will be illegal clarifies some things about overload resolution. For example,
class A {
private:
A& operator=(const A&);
};
class B : public A {
public:
operator int() const;
B& operator=(int);
};
void f(B& b1, const B& b2)
{ b1 = b2; }
is illegal because the implicitly-declared B::operator=(const B&)
is the better overload but the implicit definition is ill-formed. Without that declaration, you might think the compiler should implicitly convert b2
to int
and then assign that to b1
.
I think the distinction between the two depends on the details of your specific implementation (and doesn't make much difference). For what it's worth, Comeau gives this:
"ComeauTest.c", line 7: error: "A &A::operator=(const A &)" (declared at line 4) is
inaccessible
struct B : A
^
detected during implicit generation of "B &B::operator=(const B &)"
at line 16
1 error detected in the compilation of "ComeauTest.c".
So on that compiler, it detects the error "during" the implicit generation of B's assignment operator. In other words, it tries to generate it, and finds that it can't. Whether it detects it as it's writing it out, or by looking at A
directly, doesn't really matter.
This is what happens :
struct A
{
private:
A& operator = ( const A& );
};
struct B : A
{
B& operator = ( const B& other )
{
A::operator=( other );
return *this;
}
};
int main()
{
B b1;
B b2;
b1 = b2;
return 0;
}
The default operator= tries to call A::operator=, which is private.
The standard seems to agree with you. Quoting from the current draft:
§12.8/8:
If the class definition does not explicitly declare a copy constructor and there is no user-declared move constructor, a copy constructor is implicitly declared as defaulted (8.4).
§12.8/12:
A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has: […]
- a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor […]
So the synthesized copy constructor is declared and defined, but defined as deleted.
精彩评论