This is an annotated version of the example code that is located
here, without the comments.
#include <stdio.h>
#include <stream.h>
#include <stdlib.h>
#include <string.h>
class foo {
public: // first we do all
the public interface methods
Anything in the public section can be used by other parts of the
program. These are put first to emphasize that these are the only methods
and data that can be used by the outside world. There need to be
methods declared here to access the private data if the outside program
is going to read or write the private data.
If you want the outside program to have access, you need at least one method to read and one to write each private data element. Some private data is used by the class and is not available to the user. Traditionally, these access routine are called set and get methods.
// these are used to put values in the private
data elements
void set_a(int x) { a=x;}
This is a method used to set the value of on eof the private date
elements. All the code for the method is included right here. This is called
an inline method. See the set_title() method below for an
example of a method that is not inline. Usually, if the method is only
a few lines long, it is best written inline. Longer functions should be
written outside the class. This looks like an ordinary function definition
because it is. C++ methods can do anything any other function can do. Note
that the variable a is not defined in the method. The data elements of
the class are available to the methods as if they were passed into the
methods. They don't appear in the function header, but are visible in the
function as if they were local variables. So in this case, setting a to
x copies the value passed into the method into the private data element
a.
void set_b(int x) { b=x;}
void set_title(char *);
This method only has the function header here. The function body
is defined below, outside the class. But since the function header is located
here inside the public section of the class, it is a public method of the
class.
// these are used to get the values from the
private data elements
int get_a() { return(a);}
int get_b() { return(b);}
These are much like the set methods. Their purpose is to copy information
from the private data elements to the outside world. Again, you don't have
to declare the data elements, they are already there.
// these are the constructors
foo() { a = 0; b = 0; title = NULL;}
// default constructor
foo(int x) { a=x; b = 0; title = NULL; }
foo(int x,int y) { a= x; b = y; title=NULL;}
// notice that one constructor can call another
// and they can call other methods
foo(int x,int y,char * str) : a(x),b(y) { set_title(str);}
One of the goals of C++ is to prevent uninitialized variables. So
every class has a constructor. A constructor is a special method
that is called whenever a variable of the type of the class is created.
A variable of the class type is called an instance of the class.
There are several constructors here. C++ can allow several methods with
the same name because the true name of a function is the combination of
the return type, the function name and the function parameters. SO
in this case, foo() and foo(int x) are different because, while they have
the same return type (nothing) and the same name (foo), they have different
arguments. The combination of things that make up the true name is called
the signature. It is very common to have multiple constructors
to allow the user to make use of various bits of information they might
have. If they know nothing, the first constructor will initialize everything
to 0. If they know the value of a, then the second one is better. The constructors
are called in a way that looks like a function call. The constructor with
no arguments is called the default constructor. It is used when
you don't specify anything. It is also used when you create arrays. The
examples in the main() function below show the different constructor usages.
// these are defined outside the class declaration
int bigger();
void print_title();
/* there is only one destructor. Note that the
only
way for title to be non-null
is if we set the title
so we should delete the space
we created
*/
~foo() { cout << "the destructor is running"
<< endl;
if(title != NULL) delete [] title;}
Many times a class allocates memory at runtime to make space for
user input. It is important that this space get returned to the operating
system when the class is finished with it to prevent memory from running
out. C++ has no automatic memory cleanup (garbage collection) so you must
do it. The simplest way is to put this job in the destructor. The
destructor is another special method that is called when the instance of
the class is no longer in use. If you create an instance of the class in
a function, when the function exits the instance disappears and the destructor
is called. In this class, since the constructors all set the string pointer
element to NULL, we know that if the pointer is non-null, we should call
delete to return the memory we got using new.
private: // these are private data, not
visible outside the class
Any class elements, either data or functions that are placed inside
the private section, cannot be used directly by the outside world.
So if we have an instance of this class called X, we are not allowed to
use the reference, X.a or to call X.set_length(), as these are private.
Other class methods may call private methods or use private data.
int a,b;
char *title;
// private methods can only be called by other
class methods
void set_length() { a = strlen(title);}
}; // class foo
The function bigger() is declared as a public method on the class
foo. But the code for it is not within the class. To make sure that both
the compiler and the user knows that this function is part of the class,
we use the scope resolution operator to connect the function to
the class. All external class methods start with a return type as usual
and then have the name of the function with a prefix of class_name::. The
class name in this case is foo and the :: is the scope resolution operator.
Note that the data elements a and b are used as if they were already defined,
just like the inline functions above.
int
foo::bigger()
{
if(a < b) return(b);
return(a);
} // bigger
void
foo::set_title(char * str)
{
// note the use of cerr to print the error to stderr
if( (title = new char[strlen(str)+1]) == NULL) {
cerr << "no memory for to
save title :" << str << ":" << endl;
return;
}
(void) strcpy(title,str);
set_length();
} // set_title
In foo::print_title, we check for NULL before printing. In general, it is wise to check if a pointer is null before using it.
void
foo::print_title()
{
if(title != NULL)
cout << title << endl;
else
cout << "NULL" << endl;
} // print_title
int
main(int argc, char **argv)
{
foo X,Y(6),Z(7,8),W(1,2,"hello");
printf("X.a = %d X.b = %d ",X.get_a(),X.get_b());
X.print_title();
printf("Y.a = %d Y.b = %d ",Y.get_a(),Y.get_b());
Y.print_title();
printf("Z.a = %d Z.b = %d ",Z.get_a(),Z.get_b());
Z.print_title();
printf("W.a = %d W.b = %d ",W.get_a(),W.get_b());
W.print_title();
/*
here is what I get when I run this with g++
X.a = 0. X.b = 0 NULL
Y.a = 6. Y.b = 0 NULL
Z.a = 7. Z.b = 8 NULL
W.a = 5. W.b = 2 hello
the destructor is running
the destructor is running
the destructor is running
the destructor is running
*/
/* the following statements are illegal
remove the comment markers and see
what your compiler does
with them
*/
// X.a = 5;
// cout << "a = " << X.a <<
endl;
// X.set_length();
/* here are the errors that g++ gives me
class.cc: In function `int main(int, char **)':
class.cc:100: member `a' is a private member of class `foo'
class.cc:101: member `a' is a private member of class `foo'
class.cc:39: `void foo::set_length()' is private
class.cc:102: within this context
*/
} // main