Introduction t o Object-Oriented Programming
The most widely used object-oriented programming language to- day is C++. C++ provides classes—which are its objects. Classes really distinguish C++ from C. In fact, before the name C++ was coined, the C++ language was called “C with classes.”
This chapter attempts to expose you to the world of object- oriented programming, often called OOP. You will probably not become a master of OOP in these few short pages, however, you are ready to begin expanding your C++ knowledge.
This chapter introduces the following concepts:
-
C++ classes
-
Member functions
-
Constructors
-
Destructors
This chapter concludes your introduction to the C++ language. After mastering the techniques taught in this book, you will be ready to modify the mailing list program in Appendix F to suit your own needs.
What Is a Class ?
A class is a user-defined data type that resembles a structure. A class can have data members, but unlike the structures you have seen thus far, classes can also have member functions. The data members can be of any type, whether defined by the language or by you. The member functions can manipulate the data, create and destroy class variables, and even redefine C++’s operators to act on the class objects.
Classes have several types of members, but they all fall into two categories: data members and member functions.
Data Member s
Data members can be of any type. Here is a simple class:
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e
} ;
Notice how this class resembles structures you have already
seen, with the exception of the publi c keyword. The Spher e class has four data members: r , x, y, and z. In this case, the publi c keyword plays an important role; it identifies the class Spher e as a structure. As a matter of fact, in C++, a public class is physically identical to a structure. For now, ignore the publi c keyword; it is explained later in this chapter.
Member Function s
A class can also have member functions (members of a class that manipulate data members). This is one of the primary features that distinguishes a class from a structure. Here is the Spher e class again, with member functions added:
#i ncl ude <mat h. h>
const f l oat PI = 3. 14159;
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e
Spher e( f l oat xcoor d, f l oat ycoor d, f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e() { }
f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
This Spher e class has four member functions: Spher e() , ~Spher e() ,
Constructors create and initialize class data.
vol ume() , and sur f ace_ar ea() . The class is losing its similarity to a structure. These member functions are very short. (The one with the strange name of ~Spher e() has no code in it.) If the codes of the member functions were much longer, only the prototypes would appear in the class, and the code for the member functions would follow later in the program.
C++ programmers call class data objects because classes do more than simply hold data. Classes act on data; in effect, a class is an object that manipulates itself. All the data you have seen so far in this book is passive data (data that has been manipulated by code in the program). Classes’ member functions actually manipulate class data.
In this example, the class member Spher e() is a special function. It is a constructor function, and its name must always be the same as its class. Its primary use is declaring a new instance of the class.
Examples
- The
following program uses the Spher e() class to initialize a class variable (called a class instance) and print it.
/ / Fil ename: C32CON. CPP
/ / Demonst r at es use of a cl ass const r uct or f unct i on.
#i ncl ude <i ost r eam. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e Spher e( f l oat xcoor d, f l oat ycoor d,
f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e() { }
f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
cout << “ X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
r et ur n;
}
Destructors erase class data.
Indeed, this program looks different from those you have seen so far. This example is your first true exposure to OOP programming. Here is the output of this program:
X = 1, Y = 2, Z = 3, R = 4
This program illustrates the Spher e() constructor function. The constructor function is the only member function called by the program. Notice the ~Spher e() member function constructed s, and initialized its data members as well.
The other special function is the destructor function,
~Spher e() . Notice that it also has the same name as the class, but with a tilde (~) as a prefix. The destructor function never takes arguments, and never returns values. Also notice that this destructor doesn’t do anything. Most destructors do very little. If a destructor has no real purpose, you do not have to specify it. When the class variable goes out of scope, the memory allocated for that class variable is returned to the system (in other words, an automatic destruction oc- curs). Programmers use destructor functions to free memory occupied by class data in advanced C++ applications.
Similarly, if a constructor doesn’t serve any specific function, you aren’t required to declare one. C++ allocates memory for a class variable when you define the class variable, just as it does for all other variables. As you learn more about C++ programming, especially when you begin using the ad- vanced concept of dynamic memory allocation, constructors and destructors become more useful.
- To illustrate that the ~Spher e() destructor does get called (it
just doesn’t do anything), you can put a cout statement in the constructor as seen in the next program:
/ / Fil ename: C32DES. CPP
/ / Demonst r at es use of a cl ass dest r uct or f unct i on.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e Spher e( f l oat xcoor d, f l oat ycoor d,
f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n( voi d)
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
/ / Const r uct a cl ass i nst ance.
cout << “ X = “ << s. x << “ , Y = “
<< s. y << “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
r et ur n;
}
Here is the output of this program:
X = 1, Y = 2, Z = 3, R = 4
Spher e ( 1, 2, 3, 4) dest r oyed
Notice that mai n() did not explicitly call the destructor function, but ~Spher e() was called automatically when the class instance went out of scope.
- The
other member functions have been waiting to be used. The following program uses the vol ume() and sur f ace_ar ea() functions:
/ / Fil ename: C32MEM. CPP
/ / Demonst r at es use of cl ass member f unct i ons.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e Spher e( f l oat xcoor d, f l oat ycoor d,
f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ; / / End of cl ass.
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
cout << “ X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
cout << “ The vol ume i s “ << s. vol ume() << “ \
n” ; cout << “ The sur f ace ar ea i s “
<< s. sur f ace_ar ea() << “ \ n” ;
}
The vol ume() and sur f ace_ar ea() functions could have been made in-line. This means that the compiler embeds the functions in the code, rather than calling them as functions. In C32MEM.CPP, there is essentially a separate function that is called using the data in Spher e() . By making it in-line,
Spher e() essentially becomes a macro and is expanded in the code.
- In the following program, vol ume() has been changed to an in-line
function, creating a more efficient program:
/ / Fil ename: C32MEM1. CPP
/ / Demonst r at es use of i n- li ne cl ass member f unct i ons.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e
Spher e( f l oat xcoor d, f l oat ycoor d, f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
i nli ne f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
cout << “ X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
cout << “ The vol ume i s “ << s. vol ume() << “ \
n” ;
cout << “ The sur f ace ar ea i s “ << s. sur f ace_ar ea() << “ \ n” ;
}
The inline functions expand to look like this to the compiler:
/ / C32MEM1A. CPP
/ / Demonst r at es use of i n- li ne cl ass member f unct i ons.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e
Spher e( f l oat xcoor d, f l oat ycoor d, f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
i nli ne f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
cout << “ X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
cout << “ The vol ume i s “ << ( s. r * s. r * s. r * 4 * PI / 3)
<< “ \ n” ;
cout << “ The sur f ace ar ea i s “ << s. sur f ace_ar ea() << “ \ n” ;
}
The advantage of using in-line functions is that they execute faster—there’s no function-call overhead involved because no function is actually called. The disadvantage is that if your functions are used frequently, your programs become larger and larger as functions are expanded.
Default Member Argument s
You can also give member functions arguments by default. Assume by default that the y coordinate of a sphere will be 2.0, the z coordinate will be 2.5, and the radius will be 1.0. Rewriting the previous example’s constructor function to do this results in this code:
Spher e( f l oat xcoor d, f l oat ycoor d = 2. 0, f l oat zcoor d = 2. 5, f l oat r adi us = 1. 0)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
You can create a sphere with the following instructions:
Spher e |
s( 1. 0) ; |
/ / Use all def aul t |
|
---|---|---|---|
Spher e |
t ( 1. 0, |
1. 1) ; |
/ / Overr i de y coor d |
Spher e |
u( 1. 0, |
1. 1, 1. 2) ; |
/ / Overr i de y and z |
Spher e |
v( 1. 0, |
1. 1, 1. 2, 1. 3) ; |
/ / Overr i de all def aul t s |
Examples
- Default
arguments are used in the following code.
/ / Fil ename: C32DEF. CPP
/ / Demonst r at es use of def aul t ar gument s i n
/ / cl ass member f unct i ons.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e Spher e( f l oat xcoor d, f l oat ycoor d = 2. 0,
f l oat zcoor d = 2. 5, f l oat r adi us = 1. 0)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
i nli ne f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0) ; / / use all def aul t
Spher e t ( 1. 0, 1. 1) ; / / overr i de y coor d Spher e u( 1. 0, 1. 1, 1. 2) ; / / overr i de y and z
Spher e v( 1. 0, 1. 1, 1. 2, 1. 3) ; / / overr i de all def aul t s cout << “ s: X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
cout << “ The vol ume of s i s “ << s. vol ume() << “ \ n” ;
cout << “ The sur f ace ar ea of s i s “ << s. sur f ace_ar ea() << “ \ n” ; cout << “ t : X = “ << t. x << “ , Y = “ << t. y
<< “ , Z = “ << t. z << “ , R = “ << t. r << “ \ n” ;
cout << “ The vol ume of t i s “ << t. vol ume() << “ \ n” ;
cout << “ The sur f ace ar ea of t i s “ << t. sur f ace_ar ea() << “ \ n” ; cout << “ u: X = “ << u. x << “ , Y = “ << u. y
<< “ , Z = “ << u. z << “ , R = “ << u. r << “ \ n” ;
cout << “ The vol ume of u i s “ << u. vol ume() << “ \ n” ;
cout << “ The sur f ace ar ea of u i s “ << u. sur f ace_ar ea() << “ \ n” ; cout << “ v: X = “ << v. x << “ , Y = “ << v. y
<< “ , Z = “ << v. z << “ , R = “ << v. r << “ \ n” ;
cout << “ The vol ume of v i s “ << v. vol ume() << “ \ n” ;
cout << “ The sur f ace ar ea of v i s “ << v. sur f ace_ar ea() << “ \ n” ; r et ur n;
}
Here is the output from this program:
s: X = 1, Y = 2, Z = 2. 5, R = 1
The vol ume of s i s 4. 188787
The sur f ace ar ea of s i s 12. 56636
t : X = 1, Y = 1. 1, Z = 2. 5, R = 1
The vol ume of t i s 4. 188787
The sur f ace ar ea of t i s 12. 56636 u: X = 1, Y = 1. 1, Z = 1. 2, R = 1
The vol ume of u i s 4. 188787
The sur f ace ar ea of u i s 12. 56636
v: X = 1, Y = 1. 1, Z = 1. 2, R = 1. 3
The vol ume of v i s 9. 202764
The sur f ace ar ea of v i s 21. 237148
Spher e |
( 1, |
1. 1, |
1. 2, |
1. 3) dest r oyed |
---|---|---|---|---|
Spher e |
( 1, |
1. 1, |
1. 2, |
1) dest r oyed |
Spher e |
( 1, |
1. 1, |
2. 5, |
1) dest r oyed |
Spher e ( 1, 2, 2. 5, 1) dest r oyed
Notice that when you use a default value, you must also use the other default values to its right. Similarly, once you define a function’s parameter as having a default value, every parameter to its right must have a default value as well.
- You
also can call more than one constructor; this is called overloading the constructor. When having more than one constructor, all with the same name of the class, you must give them each a different parameter list so the compiler can determine which one you intend to use. A common use of overloaded constructors is to create an uninitialized object on the receiving end of an assignment, as you see done here:
/ / C32OVCON. CPP
/ / Demonst r at es use of over l oaded const r uct or s.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
publ i c:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e Spher e() { / * doesn’ t do anyt hi ng. . . * / } Spher e( f l oat xcoor d, f l oat ycoor d,
f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
i nli ne f l oat vol ume()
{
r et ur n (r * r * r * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n (r * r * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
Spher e t ; / / No par amet er s ( an uni ni t i ali zed spher e) .
cout << “ X = “ << s. x << “ , Y = “ << s. y
<< “ , Z = “ << s. z << “ , R = “ << s. r << “ \ n” ;
t = s;
cout << “ The vol ume of t i s “ << t. vol ume() << “ \ n” ; cout << “ The sur f ace ar ea of t i s “ << t. sur f ace_ar ea()
<< “ \ n” ;
r et ur n;
}
Class Member Visibilit y
Recall that the Spher e() class had the label publi c . Declaring the publi c label is necessary because, by default, all members of a class are pr i vat e . Private members cannot be accessed by anything but a member function. In order for data or member functions to be used by other programs, they must be explicitly declared publi c . In the case of the Spher e() class, you probably want to hide the actual data from other classes. This protects the data’s integrity. The next program adds a cube() and squar e() function to do some of the work of the vol ume() and sur f ace_ar ea() functions. There is no need for other functions to use those member functions.
/ / Fil ename: C32VI SI B. CPP
/ / Demonst r at es use of cl ass vi si bili t y l abel s.
#i ncl ude <i ost r eam. h> #i ncl ude <mat h. h>
const f l oat PI = 3. 14159; / / Appr oxi mat e val ue of pi .
/ / A spher e cl ass. cl ass Spher e
{
pr i vat e:
f l oat r ; / / Radi us of spher e
f l oat x, y, z; / / Coor di nat es of spher e f l oat cube() { r et ur n (r * r * r) ; }
f l oat squar e() { r et ur n (r * r) ; }
publ i c:
Spher e( f l oat xcoor d, f l oat ycoor d, f l oat zcoor d, f l oat r adi us)
{ x = xcoor d; y = ycoor d; z = zcoor d; r = r adi us; }
~Spher e()
{
cout << “ Spher e (“ << x << “ , “ << y
<< “ , “ << z << “ , “ << r << “) dest r oyed\ n” ;
}
f l oat vol ume()
{
r et ur n ( cube() * 4 * PI / 3) ;
}
f l oat sur f ace_ar ea()
{
r et ur n ( squar e() * 4 * PI ) ;
}
} ;
voi d mai n()
{
Spher e s( 1. 0, 2. 0, 3. 0, 4. 0) ;
cout << “ The vol ume i s “ << s. vol ume() << “ \
n” ;
cout << “ The sur f ace ar ea i s “ << s. sur f ace_ar ea() << “ \ n” ; r et ur n;
}
Notice that the line showing the data members had to be
removed from mai n() . The data members are no longer directly accessible except by a member function of class Spher e . In other words, mai n() can never directly manipulate data members such as r and z, even though it calls the constructor function that created them. The private member data is only visible in the member functions. This is the true power of data hiding; even your own code cannot get to the data! The advantage is that you define specific data- retrieval, data-display, and data-changing member functions that mai n() must call to manipulate member data. Through these member functions, you set up a buffer between your program and the program’s data structures. If you change the way the data is stored, you do not have to change mai n() or any functions that mai n() calls. You only have to change the member functions of that class.
Review Question s
The answers to the review questions are in Appendix B.
-
What
are the two types of class members called?
-
Is a constructor always necessary?
-
Is a destructor always necessary?
-
What
is the default visibility of a class data member?
-
How do you make a class member visible outside its class?
Review Exercis e
Construct a class to hold personnel records. Use the following data members, and keep them private:
char name[ 25];
f l oat sal ar y;
char dat e_of _bi r t h[ 9];
Create two constructors, one to initialize the record with its necessary values and another to create an uninitialized record. Create member functions to alter the individual’s name, salary, and date of birth.
Summary
You have now been introduced to classes, the data type that distinguishes C++ from its predecessor, C. This was only a cursory glimpse of object-oriented programming. However, you saw that OOP offers an advanced view of your data, combining the data with the member functions that manipulate that data. If you desire to learn more about C++ and become a “guru” of sorts, try Using Microsoft C/C++ 7 (Que, 0-88022-809-1).