⬆️ ⬇️

In C ++, the unit of encapsulation is the class.

The title of the article actually represents not one statement, but two, although both of them are known:

  1. In C ++, the unit of encapsulation is a class — not a separate object ([Stroustrup3e], 24.3.7.4).
  2. In C ++, the unit of encapsulation is a class — and not a class with its lower hierarchy.


The second statement is not trivial, since, for example, the following interpretation of protected members ([Stroustrup3e], 15.3) is popular:

If a member is protected, its name can only be used in member functions and friends of the class in which it is declared and the classes derived from it.


In fact, this statement is, in mathematical terms, necessary, but not sufficient:

To use the name of a protected member, it is necessary, but not enough, to call the name from a member function or a friend of the class in which it is declared, or from classes derived from it.

The statement becomes necessary and sufficient only when adding a clarification ([Stroustrup3e], 15.3.1):

A derived class can access protected members of a base class only for objects of its own type.


For demonstration, here is the code:

class Base { protected: void protected_f() {} private: void private_f() {} public: void base_f() { private_f(); //correct: *this object therefore object of own class Base Base b; b.private_f(); //correct: b is object of class Base (1) } }; class Derived : public Base { void derived_f() { Derived d; d.protected_f(); //correct: d is object of class Derived therefore d->Derived::f() is called (2) Base b; b.protected_f(); //compiler error: Base::f() is protected (3) ((Derived*)(&b))->protected_f(); //dangerous non-dynamic downcast, but w/o compiler error (4) } }; 


The first statement is trivial and is demonstrated (1): this-> base_f () calls b.private_f (), the call is correct, because although * this and b are different objects, they are objects of the same Base class.

The second statement is demonstrated by (2) and (3). Call (2) is correct because the name protected_f is inherited in the class Derived and this-> derived_f () calls d.Derived :: protected_f () the function of the class Derived, and * this and d are different objects of the same class Derived. Call (3) is not correct due to an attempt to violate encapsulation: this-> derived_f () of the * this object of the Derived class tries to call the protected Base :: protected_f () of the object b of the Base class, that is, go beyond its encapsulation unit - the class of Derived in Base-Derived hierarchy. this-> derived_f () has the right to call only those protected members that belong to objects of the same Derived class as * this itself, for example, Derived :: protected_f ().

Line (4) demonstrates that the second part of the statement about the encapsulation unit is easier than the first: if for accessing private members from outside the encapsulation unit, it is necessary to use tricks such as low-level transformation of instances of objects or redefining keywords, then access to protected members with encapsulation violations is sufficient to downgrade C-style cast pointers.



In conclusion, we note that the duality of the statement about the unit of encapsulation can be viewed from several points of view:





Literature



[Stroustrup3e] B. Straustrup. C ++ programming language, 3rd ed. / Trans. from English - SPb .; M .: “Nevsky dialect” - “Publishing house BINOM”, 1991


')

Source: https://habr.com/ru/post/170127/



All Articles