Question About The C++ Programming Language
In Chapter 24.3.4 of the book The C++ Programming Language it said that
class Cfield : public Field{ /*...*/ }
This expresses the notion that a
Cfield
really is a kind of Field, allows notational convenience when writing aCfield
function that uses a member of the Field part of theCfield
, and - most importantly - allows aCfield
to override Field virtual functions. The snag is that theCfield*
toField*
conversion implied in the declaration ofCfield
defeats all attempts to control access to theField
:void g(Cfield* p) { *p = "asdf"; // access to Fiel开发者_开发问答d controlled by Cfield's assignment operator: // p->Cfield::operator=("asdf") Field* q = p; // implicit Cfield* to Field* conversion *q = "asdf" // OOPS! no control }
What I DO NOT understand here, is the bolded sentence. How did Cfield
defeat the attempt to control access to Field
?
Actually, the last line of the code:
*q = "asdf";
will call Field::operator=("asdf")
, so how did Cfield
defeat the attempt to control access to Field
?
CField
instances are supposed to provide controlled (i.e. checked in some way by CField::operator=()
) access to the Field
base class data. But if you implicitly cast a CField *
to a Field *
, that and then dereference it, that control is gone because you pick up Field::operator=()
.
I agree that this is not the clearest of BS's writings, and seems to me to be a bit of a none-issue - you can always get "uncontrolled access" to anything if you put your mind to it.
I guess it refers to the problem that the assignment operator of Cfield
might do special things that are required to keep the state of the object consistent. By using the assignment operator of the superclass, invariants might be broken.
Let's give a concrete example:
struct Field {
Field(char const* s): string(s) {}
char const* string;
};
struct CField: Field {
CField(char const* s): Field(s), length(s ? ::strlen(s) : 0) {}
std::size_t length;
};
This is a very basic kind of string, that does not allow modification of the string it refers too. CField
augments the Field
class by caching the length of the string.
Now, in action:
void foo(CField& cf) { // 0
cf = "foo"; // 1
Field& f = cf; // 2
f = "foobar"; // 3
}
What happens ?
- line 0: state is unknown
- line 1: call to
CField& CField::operator=(CField const&)
, which creates a temporaryCField
(using the constructor),cf.string
is"foo"
andcf.length
is3
- line 2: same object, access via
Field
directly - line 3: call to
Field& Field::operator=(Field const&)
, which creates a temporaryField
(using the constructor),cf.string
is"foobar"
andcf.length
is3
(unchanged)
As you can note, the invariant that length
caches the length of the string
is broken because of the unprotected access to string
via Field&
.
精彩评论