Encapsulation and Abstract concepts of oops

 Encapsulation is often confused with information hiding. However, these terms are not interchangeable. Encapsulation is the ability to bundle related data and functionality within a single, autonomous entity called a class. For example, a class called LoggerFile might bundle data members such as the log file's path; a buffer of data waiting to be written to that file; and member functions that open, read, write, and close that file, as in the following code listing:


class LogFile

{

public:

 int Open();

 int Read(char *buff);

 int Write(const char *buff);

 int Close();

private:

 FILE *logfile;

 bool _open;

//...additional data members

};In procedural languages such as C, you declare these data members and the associated functions separately. Consequently, a global function that opens a log file may be mistakenly called to open a file that has already been opened. Worse yet, users might delete a log file and then attempt to write to it. By bundling the data and functionality in an autonomous class, it's much easier to avert such human errors, because the class maintains the state of the file and is therefore able to prevent such errors.


Abstract classes can be used to define the C++ version of interfaces. A C++ abstract class describes functionality shared by objects of all concrete classes that are explicitly listed (perhaps indirectly) as subclasses. An object may play multiple roles by inheriting and implementing multiple interfaces. (The language doesn't directly support notions that an object may play different roles at different times, or that a role is implemented by a collection of objects, but these effects can usually be had in one way or another.) 


C++ interface-style abstract classes take an idiomatic form: 


class AnInterface {

public:

  virtual T1   aService(T2, T3) = 0;

  ...

  virtual T4   anAttribute() const = 0; // get value

  virtual void anAttribute(T4) = 0;     // set value

  ...

  virtual T5   aReadOnlyAttribute() const = 0;


  virtual ~AnInterface() {}


protected:

  AnInterface() {}

};


Ideally, the types T should consist only of pass-by-value scalar types (int, float, enum, ...), collections of them (structs, ...) and/or pointers to objects of classes also defined via abstract classes (thus representing handles). The lack of native by-value string and array types in C++ is a problem here. One occasionally attractive alternative is to always contain fixed arrays in structs. But in practice, you can make ADT-style types work OK too. This way you can sometimes obtain simpler mechanics and also avoid value copying. ADT-style fake pointer classes may also be used instead of raw pointers for handle types, although there is no perfect way to do this. 


Abstract classes sometimes lend themselves to parameterization over some type used in one or more signatures. (Some nice examples are described in Barton and Nachman's book.) Beyond the template prefix, nothing much changes except for the pragmatic problems of dealing with templates in C++. These include for example the fact that template instantiation errors are not usually reported until link time. This is best combatted by prefacing each template with a brief comment about what operations are assumed to be supported on the type (e.g., a < comparison). 


Since interface classes cannot be directly instantiated, yet serve as virtual base classes for implementations, the constructors should take no arguments and should be listed as protected. Also, for similar reasons, abstract classes should have a no-op virtual destructor, not one listed as ... = 0. Depending on your compiler, you might need to define the no-op constructor and destructor operations outside the class declaration in a separate .C file. 

All comments are reviewed by the administrator, before they are published.

Post a Comment (0)
Previous Post Next Post