Previous Table of Contents Next


Part II
Moving from C to C++

Chapter 5
A Touch of Class

One of the key ideas in C++ is active types: you define a type in terms of what you can do with it. You ran specify built-in operations and functions for the type. Because the operations are built into the type, certain kinds of programming are much easier.

If you create your own string type, for example, what would it mean to add two strings? How might they be initialized? If you have a mathematical bent, you could define a complex-number type and build in the ability to do complex-number arithmetic. Or you might have a pizza-shop program and define all the operations you can perform on a pizza.

In C++, the word class describes any kind of user-defined type. Classes can include built-in function support and virtually become part of the language once declared. You can freely define new items with a class name, just as you can with int, float, double, and so on. This is one of many ways in which C++ is programmer-friendly.

Developing Class: A Better String Type

One of the major complaints that people have when they learn C is that character strings are cumbersome. In Basic, for example, you can do this:

str1 = “My name is ”
str2 = “Bill.”
str3 = str1 + str2

And now str3 contains the message “My name is Bill.” In standard C, this operation would take more work:

strcpy(str1, “My name is ”);
strcpy(str2, “Bill.”);
strcpy(str3, str1);
strcat(str3, str2);

In this chapter and in the two that follow, we’ll build a new string type that is every bit as good as the string type in Basic. In many ways, the new string type will be better than anything in Basic, because you have ultimate control over the fate of the type. When you work with classes in C++, you can add new capabilities any time you want to.

From now on, I’ll follow C++ terminology in using class whenever I talk about a user-defined type. (This term applies to structures, by the way, as well as to anything created with the class keyword.) When you see the term class, you should think of a new type that has its own characteristics and capabilities.

To create a class, use the class keyword with the following syntax:

class class_name {
    declarations
};

In C++, the declarations can include function declarations as well as data declarations. First, let’s look at the simplest possible string class:

class CStr {
   char sData[256];
};

The name CStr is the class name, and sData is its contents. This simple class stores the string data. Now let’s add some functions:

class CStr {
   char sData[256];
public:
   char *get(void);
   int getlength(void);
   void cpy(char *s);
   void cat(char *s);
};

The four functions—get, getlength, cpy, and cat—operate on data stored in the class. What’s the big deal? Why is it better to define functions inside the class rather than use functions—such as C’s strcpy function—that operate externally on the class?

This is a simple class, and at this point it doesn’t provide many practical advantages. There is one benefit, however: the string data, sData, is private to the class. No one can touch it except the class’s own functions. If you later rewrite the class so that its internal implementation is completely different—and later in this chapter we will do that —code that uses this class won’t break. This is a big advantage of classes.

Member Functions: A Class Act

You can write definitions for these functions just as you would for any other function, with one difference: the function name must be preceded by a special prefix.

class_name::

The two colons (::) form a single operator, called the scope operator. This operator, along with the class name, clarifies which function you’re talking about. More than one class could have a function with the same name. For example, a class named CMyclass could also have a function named get. Outside the class declarations,

CMyclass::get

refers to the version of the get function belonging to CMyclass, and

CStr::get

refers to the version of the get function belonging to CStr. The complete syntax for a class-member function definition is as follows:

return_type class_name::function_name (arguments) {
          statements
}

In this case, the class name is CStr. In the function definitions that follow, remember that “CStr::” is simply part of the function name. Aside from this name prefix, these function definitions look just like those you might write for ordinary functions.

#include <string.h>
char *CStr::get(void) { // Return ptr to string data.
return sData;
}

int CStr::getlength(void) { // Return length.
return strlen(sData);
}

void CStr::cpy(char *s) { // Copy string arg
return strcpy(sData, s);
}

void CStr::cat(char *s) { // Concatenate string arg
return strcat(sData, s); // onto object.
}

Don’t get thrown by the pointer syntax in these function definitions. Remember that any function that returns a pointer is declared with the indirection operator (*) to the left of the name:

char *strcpy(char *s1, char *s2);

With CStr member functions, “CStr::” is simply part of the name. So the declaration of the get function has an asterisk to the left of CStr::.

Figure 5.1 summarizes how declarations and function definitions are linked by the class name, which in this case is CStr.


Figure 5.1  CStr class declaration and function definitions.

The Deadly Semi: Watch Out for That Syntax!

One syntax error you’re sure to make a few times—unless you’re careful—is to use too many or too few semicolons. Class declarations end with them; function definitions do not.

As a general rule, C and C++ statements do not follow a terminating brace (})with a semicolon. All function definitions follow this rule:

char *CStr::get(void) {
   return sData;
}

However, class, struct, and union declarations require a semicolon after the brace.

class CStr {
   char sData[256];
public:
   char *get(void);
   int getlength(void);
   void cpy(char *s);
   void cat(char *s);
};

This rule may seem one of the more arbitrary rules in C and C++, but it does have the benefit of helping the compiler to distinguish between declarations and function definitions. All declarations except function definitions require the terminating semicolon. So a function prototype ends with a semicolon whether or not it’s inside a class:

char *get(void);

What’s an Object, Anyway?

Together, a class declaration and function definitions, define how the string type works. The next step is to use the CStr declaration to create some strings:

CStr str1, str2, str3;

In C++, as soon as you have successfully declared a class, you can use the class name to declare variables, just as you can with int, long, float, double, and so on. The class name takes on the same status in the language that data-type keywords have.


Previous Table of Contents Next