Effective C++ item 5: Know what functions C++ silently writes and calls.

If you have an empty class, compilers will declare a default constructor, a copy constructor, a copy assignment operator and a destructor for you. So

1
class Empty{};

will be essentially the same as

1
2
3
4
5
6
7
8
9
class Empty
{
public:
Empty(){...}
Empty(const Empty& rhs){...}
~Empty(){...}

Empty& operator=(const Empty& rhs){...}
};

Let’s see an example of how compiler will refuse to generate some code for you and you should write your own code explicitly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
class Pair
{
public:
Pair(std::string& left, int right):
leftValue(left), rightValue(right)
{}
private:
std::string& leftValue;
const int rightValue;
};

int main()
{
std::string one("1");
std::string two("2");
Pair a(one, 1);
Pair b(two, 2);

a = b;
return 0;
}

will have such compilation errors:

1
2
3
4
5
test.cpp: In member function ‘Pair& Pair::operator=(const Pair&)’:
test.cpp:2:7: error: non-static reference member ‘std::string& Pair::leftValue’, can’t use default assignment operator
test.cpp:2:7: error: non-static const member ‘const int Pair::rightValue’, can’t use default assignment operator
test.cpp: In function ‘int main()’:
test.cpp:20:9: note: synthesized method ‘Pair& Pair::operator=(const Pair&)’ first required here

It means that the compiler refuse to generate copy assignment constructor for line 20 when we are going to assign b to a. Why? The simple answer is that compilers don’t know what to do in copy constructor. Since C++ doesn’t provide a way to make a reference refer to a different object, neither can we modify a const object.

So the solution is if you want to support copy assignment in a class containing reference members or const members, you must define the copy assignment operator yourself. Finally, compilers reject implicit copy assignment operators in derived classes that inherit from base classes declaring the copy assignment operator private, in other words, if base classes prevent doing something such as copy assignment, derived classes inherit that property from base classes implicitly (unless you explicitly define copy assignment operator in derived classes). After all, compiler-generated copy assignment operators for derived classes are supposed to handle base class parts too, but in doing so, they certainly can’t invoke member functions the derived class has no right to call.

Reference:
“Effective C++” Third Edition by Scott Meyers.