Previous Table of Contents Next


C++ also supports an inline keyword so that you can selectively make any function an inline function. But, as I said, it’s automatic inside a class declaration.

Structures as a Special Case of Classes

How is a class different from a structure? If you’ve used structures in C, you’ll recall that they’re collections of data that can be of varying types. How is this different from a class?

It’s tempting to give the answer that classes can have member functions and structures can’t—but that’s not true. C++ will not only compile all your code that uses struct, but it will also let you add member functions to those same structures!

Strangely enough, the only difference between a data type declared with struct and one declared with class comes down to what’s public and what’s private. It is not a matter of whether or not it has member functions. In a type declared with struct, all the members are public. This is necessary to give C++ maximum compatibility with C. In C, there is no concept of private data, so it’s as if everything in C were declared public.

The situation is potentially confusing because the word class refers not just to things created with the keyword class, but also to things created with struct and union. Think of structures and unions as special cases of classes in which everything is public. When you use the class keyword, everything is private by default—which is the preferred way of creating classes in a language (namely C++) that tries to encourage encapsulation.

Classes in Perspective

This has been a long chapter, yet classes are a simple and elegant idea. A class is a user-defined type in which part of the definition of that type can include the operations that it supports. In other words, you tell me what something is by what it can do.

Encapsulation

One of the most important features of C++ classes is encapsulation. This means a clean separation between the interface of a class, which is public to the world, and the internals, which cannot be accessed by anything outside the class. Such a separation is immensely useful, because it means that you can rewrite the internals of the class without messing up the rest of the program. (The revisions must not have obvious errors, but that goes without saying.) In the old world of C, intricate connections between internals throughout a program meant that any revisions at any time—no matter how correct they were in and of themselves—could destabilize the entire system.

I’d like to report that object orientation has eliminated all causes of bugs, but you’d know I was kidding (or drinking something strong). Assiduous use of encapsulation, however, does prevent some causes of bugs.

Classes, Objects, and Instantiation

Another of the key concepts in this chapter is the distinction between classes and objects. A class is a user-defined type; an object is a thing of that type. This is not as abstract as it sounds. The class is the general mold or assembly line for a set of objects. The class determines the size, the shape, and all the properties and built-in behavior for each object. Once the class is defined, any number of objects of that class may then be defined and used for whatever purpose the program sees fit.

For each class, the number of objects of that class can range from zero to infinity.

The process of creating an object of a certain class is referred to as instantiation (an ugly word). Usually it’s easiest to replace the word instantiation with the phrase “creating objects of a particular class.” A class with zero objects has not been instantiated. The word instantiation is occasionally useful, though, for if a class has not been instantiated it normally has no effect on a program—it’s just a Platonic form, a product specification without a prototype. Certain actions are never carried out until a class is instantiated. Yet uninstantiated classes can affect a program indirectly by their relation to other classes. That’s something we’ll consider in Chapter 8 “Inheritance: C++ and Good Genes.”

But, in general, a class without an object is an idea without concrete representation. Or a factory mold that has not yet produced anything.

Classes: Reusing and Publishing

Before concluding this chapter, I should emphasize that classes become truly useful when you are dealing with large programs or creating a new type that is so powerful it can profitably be used in one program after another.

We’re on our way to creating just such a useful class with CStr. Once it’s finished, it will become a useful language extension that you can use in many programs. There is still work to do, however.

A class is most useful when you can give it to someone else and say, “Here, use this in your own programs.” To enable this class-distribution, you should organize your code as follows:

  Place your class declaration in a header file. Header files traditionally contain type information that is needed by every module in a program, so programmers use an #include directive to read this type information into each module.
  Place your function definitions (except those that are inline) into a separate file, which you compile. This file called an implementation file, typically has a .CPP or .CXX file extension. Compiling the file produces an object file, which the class user links into his or her program.

The beauty of this division is that you need not share most of your source code with people who use your class if you choose not to. You need only provide the header file and object files containing compiled code. The class users include the header file with each of their modules and then add your object file to the linker command line. They can automate the latter step by the use of make files, projects, or batch files.

With this introduction to classes, you know almost enough to write useful classes you can reuse in many programs. However, even mildly sophisticated classes such as CStr need carefully written copy constructors and operators, topics that are the subject of the next two chapters.


Previous Table of Contents Next