7.1. Classes

Up until now, we have emphasized procedural programming; in which programs are composed of procedures. The program executes procedures (functions) one at a time, placing unfinished functions on the call stack, if needed, working towards a desired end state. Functions usually exist independently from each other. C++ does provide some tools to make working with free functions easier. Functions can be grouped in a namespace declaration, or in a single compilation unit. Function overloads allow functions that perform the same task, but on different types to be given the same name.

When procedural programs run, data is passed around or returned from functions. In the late 1960’s, concerns about the cost, reliability, and maintainability of large software systems manifested in what was called a ‘software crisis’.

Very large programs comprised of many thousands of functions are inherently complex. Simply managing the names of functions in a very large program can be burdensome. When every function is effectively public, Then every function has access to every other function, even if there is no good reason for public visibility.

How to solve this problem? Abstraction. Humans deal with complexity by abstracting details away. For example: driving a car doesn’t require knowledge of the internal combustion engine; it’s enough to think of a car as simple transport.

There is nothing special about forming abstractions, people do it every day. However, in object-oriented programming this is a main focus of activity and organization. Object-oriented (OO) programming takes advantage of the natural human tendency to work with real world abstractions. In OO:

In contrast to procedural programming, object-oriented programming allows programmers to hide data and functions within a class.

A class also effectively defines a type. In other words, when you create a new class, You are creating a new type. Most classes define both:

and

Together, the data and operations form an abstract data type. Since it is you inventing the type, you also see the term user-defined type. Class, abstract data type, and user-defined type are all synonyms for the same thing.

Don’t let the new terms scare you. You have been working with classes since chapter 2. The types string, and all the sequential and associative containers, are classes. When designed correctly, a class can be manipulated with the same operations as the built-in types. Any class you create allows you to define a new type that works with the rest of C++ and the STL as if it were built into C++.

While many classes manage their own data, just as many classes store no data at all. This is normal. Because the data in a class is normally hidden, there is no way to know if a class even has data without looking at the source code.

Part of the beauty of the object-oriented abstraction is that you, the user of the class do not need to care. We use classes in the same way we use any built-in type: to get something specific done in a clear, efficient manner.

7.1.1. The basic structure of a class

Create a new class using either the class or struct keywords. The general (simplified) format is:

class class-name {
  public:
     // publicly visible class members
  private:
     // hidden class members
};

We will be adding to this basic structure over the next several chapters.

In C++, a struct is a class with default public access:

This program works because everything in a struct is publicly visible to any other component in the program.

#include <cstdio>

struct Talk {
  void hello() {
    std::puts("Hello, world!");
  }
};

int main() {
  Talk say;     // Create an object from a class
  say.hello();  // Call a function in the object
}

Note

Two things:

  1. Notice the trailing semi-colon (;) after the definition of struct Talk?

    This is required for a class or struct to compile and forgetting to include a trailing ; is a common source of error.

  2. The function main accesses the function hello using the member access operator.

    The general format is object name . member name.

Here we have a very similar program, but with one important change.

This program does not compile because everything in a class is private by default. Only objects of type Talk may use or even know about its private data.

#include <cstdio>

class Talk {
  void hello() {
    std::puts("Hello, world!");
  }
};

int main() {
  Talk say;     // Create an object from a class
  say.hello();  // Call a function in the object
}

We can fix our broken class Talk by adding public: to the class. The access specifiers public and private are used in a class or a struct to control what parts of the class may be accessed from outside the class.

class Example {
  public:             // all declarations after this point are public
    void add(int x) { // member "add" has public access
      n += x;         // OK: private Example::n can be accessed from Example::add
    }
  private:            // all declarations after this point are private
    int n = 0;        // member "n" is private
};

Try this!

  • Add an access specifier to class Talk so that it compiles and runs.

  • Add an access specifier to struct Talk so that it fails with a similar error as class Talk did before you modified it.


You have attempted of activities on this page