开发者

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 a Cfield function that uses a member of the Field part of the Cfield, and - most importantly - allows a Cfield to override Field virtual functions. The snag is that the Cfield* to Field* conversion implied in the declaration of Cfield defeats all attempts to control access to the Field:

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 temporary CField (using the constructor), cf.string is "foo" and cf.length is 3
  • line 2: same object, access via Field directly
  • line 3: call to Field& Field::operator=(Field const&), which creates a temporary Field (using the constructor), cf.string is "foobar" and cf.length is 3 (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&.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜