Item 27: Explicitly disallow use of implicitly generated member functions you don't want.
Suppose you want to write a class template, Array, whose generated classes behave like built-in C++ arrays in
every way, except they perform bounds checking. One of the design problems you would face is how to prohibit
assignment between Array objects, because assignment isn't legal for C++ arrays:
double values1[10];
double values2[10];
values1 = values2;
// error!
For most functions, this wouldn't be a problem. If you didn't want to allow a function, you simply wouldn't put it
in the class. However, the assignment operator is one of those distinguished member functions that C++, always
the helpful servant, writes for you if you neglect to write it yourself (see Item 45). What then to do?
The solution is to declare the function, operator= in this case, private. By declaring a member function
explicitly, you prevent compilers from generating their own version, and by making the function private, you
keep people from calling it.
However, the scheme isn't foolproof; member and friend functions can still call your private function. Unless,
that is, you are clever enough not to define the function. Then if you inadvertently call the function, you'll get an
error at link-time (see Item 46).
For Array, your template definition would start out like this:
template
class Array {
private:
// Don't define this function!
Array& operator=(const Array& rhs);
...
};
Now if a client tries to perform assignments on Array objects, compilers will thwart the attempt, and if you
inadvertently try it in a member or a friend function, the linker will yelp.
Don't assume from this example that this Item applies only to assignment operators. It doesn't. It applies to each
of the compiler-generated functions described in Item 45. In practice, you'll find that the behavioral similarities
between assignment and copy construction (see Items 11 and 16) almost always mean that anytime you want to
disallow use of one, you'll want to disallow use of the other, too.
Suppose you want to write a class template, Array, whose generated classes behave like built-in C++ arrays in
every way, except they perform bounds checking. One of the design problems you would face is how to prohibit
assignment between Array objects, because assignment isn't legal for C++ arrays:
double values1[10];
double values2[10];
values1 = values2;
// error!
For most functions, this wouldn't be a problem. If you didn't want to allow a function, you simply wouldn't put it
in the class. However, the assignment operator is one of those distinguished member functions that C++, always
the helpful servant, writes for you if you neglect to write it yourself (see Item 45). What then to do?
The solution is to declare the function, operator= in this case, private. By declaring a member function
explicitly, you prevent compilers from generating their own version, and by making the function private, you
keep people from calling it.
However, the scheme isn't foolproof; member and friend functions can still call your private function. Unless,
that is, you are clever enough not to define the function. Then if you inadvertently call the function, you'll get an
error at link-time (see Item 46).
For Array, your template definition would start out like this:
template
class Array {
private:
// Don't define this function!
Array& operator=(const Array& rhs);
...
};
Now if a client tries to perform assignments on Array objects, compilers will thwart the attempt, and if you
inadvertently try it in a member or a friend function, the linker will yelp.
Don't assume from this example that this Item applies only to assignment operators. It doesn't. It applies to each
of the compiler-generated functions described in Item 45. In practice, you'll find that the behavioral similarities
between assignment and copy construction (see Items 11 and 16) almost always mean that anytime you want to
disallow use of one, you'll want to disallow use of the other, too.
Comments
Post a Comment
https://gengwg.blogspot.com/