Principles of Object-Oriented Languages

 < Free Open Study > 



These days, numerous object-oriented languages (OOLs) exist. C++, Java, Visual Basic, and Object Pascal (Delphi) are but a tiny sampling of the popularity of object-oriented programming (OOP). Unlike C, object languages allow software engineers to physically group data and related functions into a single UDT called a class. When we bind together state (data) and behavior (functions) into a single named entity, we are able to model our software as entities we find in the real world.

Regardless of your language of choice, every OOL must be measured against three core principles of object technology, often termed the famed "pillars of OOP":

  • Encapsulation: How well does this language hide implementation details?

  • Inheritance: How can I reuse my source code?

  • Polymorphism: Can I treat related objects in a similar way?

Based on these traits, academics love to judge how worthy a given OO language is, not to mention the raging holy wars we developers tend to get into. To be honest, each language has pros and cons; however, and we will avoid such hostile conversations here. COM is Microsoft's binary object model, and being an object model, COM also contends with the issues of inheritance, encapsulation, and polymorphism. However, before we dive into the world of interfaces, coclasses, and class objects, we will examine the ins and outs of C++'s object standing. Later in Chapter 3, we will see how COM itself measures up against these same OO foundations.

From C Structures to C++ Classes

A class is a user-defined type, somewhat like the C structure we have already examined. However, recall that in traditional SP, the developer works with data and functions on a global level. We have seen how the C structure allows you to group related data together as one unit (the CAR structure) as opposed to a collection of separate variables. Here is another example of a C struct, this time modeling a simple employee:

click to expand
Figure 1-5: Merging related global data into a C structure.

As before, we can now create variables of type EMPLOYEE and send them around to the set of global functions in our program:

/* Global functions operating on another C structure. */ void GiveBonus(struct EMPLOYEE *e, int amount); void FireThisPerson(struct EMPLOYEE e); 

Classes take the concept of grouping related items one step further, as we can define the set of data that represents the class (often called attributes or properties), as well as the set of functions which relate to this data (called methods in OO speak). Thus, a class is a description, or blueprint, for related functionality. An object is simply a variable of a given class, sometimes referred to as an instance of the class. Figure 1-6 illustrates a class named CEmployee, based off the previous EMPLOYEE struct and related global functions:

click to expand
Figure 1-6: Merging related data and related functionality into a C++ class.

Note 

By convention, class names typically begin with a "C-" prefix.

Creating and Destroying Objects: Constructors and Destructors

Classes developed in C++ are endowed with special methods allowing an object to be constructed and destroyed in an automatic and predictable manner. Rather than requiring users of your UDT to call class-specific creation and termination methods (e.g., Init(), Terminate(), Create(), KillThisObject(), and so on), C++ classes automatically receive a default constructor and a default destructor.

Constructors provide a simple way to initialize the state data of a new object as soon as the object user creates it. The default constructor of a class takes no arguments and hence sometimes goes by the name of the "no-arg" constructor. Constructors are called automatically whenever a new instance of the class is created, will always have the same name as the class itself, and do not provide a return value. In addition to the default constructor, a given class may have any number of custom constructors that do take arguments, allowing the object user to specify exactly how the internal data should be initialized. The ability for a class to define methods of the same name with different signatures is called method overloading.

Note 

As soon as you add a custom constructor to a class definition, the default constructor is silently removed. You must specifically redefine the no- argument constructor in your class definition if you wish your class to support it.

A destructor allows the class designer to ensure any acquired resources (memory, data source connections, and whatnot) are automatically deallocated when the object is about to be destroyed. A destructor also takes the same name as the class, sporting a tilde (~) prefix, and returns nothing. Unlike constructors, destructors never take arguments and cannot be overloaded. Destructors are called automatically whenever an object is explicitly deallocated from memory using the delete keyword, or when the object naturally falls out of scope.

Building the Initial CEmployee Class

Here is an initial C++ definition for a CEmployee class that defines a single overloaded constructor with three arguments, the no-arg constructor, and the one and only destructor:

// Initial definition of the CEmployee class. class CEmployee { public:      // Must redefine no-argument constructor when overloading.      CEmployee();      CEmployee(int ID, char* name, float startingSalary);      // Declare your destructors as virtual, to ensure proper clean-up      // when casting a base class pointer to a derived class.      virtual ~CEmployee(); };   // End class definitions with a semi-colon. Easily forgotten, hard to debug.

For the time being, assume we have written simple stub code for your constructors and destructor. With this assumption aside, an object user may now create various CEmployee objects using the following syntax:

// Create two instances of the CEmployee class. void main(void) {      CEmployee Mary;                               // Calls default constructor.      CEmployee Walter(15, "Walter", 99000);        // Overloaded constructor. }    // Triggers destructor as objects fall out of scope. 

Of course we may make pointers to objects as well. The new and delete keywords allow us to dynamically allocate and deallocate objects in C++:

// Dynamically create and destroy a CEmployee object. void main(void) {      // Calls overloaded constructor.      CEmployee *pZuZu = new CEmployee(50, "ZuZu", 500);      // Calls destructor.      delete pZuZu; }
Note 

Never use the malloc() and free() functions of the C library to dynamically create or remove an object from memory, as these functions know nothing of C++ constructors and destructors!

Our simple CEmployee class is not too interesting at this point. It can be created in a handful of ways, and when it is no longer needed, the destructor will be called to perform any object cleanup. Classes become much more useful when we add internal data (which represents the state of a given object) and various public methods (to establish the behavior of the class), both of which require an understanding of encapsulation.



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net