When should I use classes in C ++

Chapter 1: Classes and objects

Programming in C ++: structure

This book is licensed under a Creative Commons license.

1.1 General

Concepts and practical implementation

In object-oriented programming, terms like classes, objects, instances, inheritance, encapsulation and so on are just thrown around. This chapter gives you an overview of the individual components of object orientation, how they are related and, above all, what their purpose is. This overview does not only apply to the C ++ programming language, but also to other object-oriented languages.

After the flight over object orientation, you will be instructed in the necessary syntax and semantics to create simple classes in C ++ yourself.

1.2 Overview

object oriented programing

There is huge hype around object-oriented programming, especially among developers who do not program object-oriented. Object orientation seems to be the non-plus-ultra, the holy grail of programming languages. Object-oriented programs appear to be fundamentally better than applications that are developed in a non-object-oriented programming language. Where does this hype about object orientation come from?

With object orientation, as the name suggests, objects are in the foreground. A program is no longer viewed as a kind of waterfall in which information flows from top to bottom. This flow concept of data does not play a role in object orientation.

If a task is solved in an object-oriented manner, objects that have to interact with one another to solve the task are worked out first. In order to be able to program object-oriented, it must first be clear what exactly are needed for objects. This of course depends on the task. If, for example, software for an ATM for withdrawing money is to be developed in an object-oriented manner, the customer and bank could prove to be necessary objects for solving the task. After all, withdrawing money is a process in which a customer enters data into an ATM and communicates electronically with a bank.

An object-oriented programming language now makes it possible to take the customer and the bank into the software. This means that in an object-oriented programming language, the objects that have been worked out are taken directly into the code and reproduced there. This simulation takes place in such a way that the properties and capabilities of the objects required to solve the problem are taken over into the code.

For example, the customer's hair color does not play a role in the development of the ATM software. However, whether he knows the PIN for his bank account is important. Therefore, the customer object could be given a property PIN. A hair color property would be nonsensical.

In order to find out the PIN from the customer, he must give it to the ATM. The customer must be able to enter a PIN. This ability would therefore be given to the corresponding object customer in the object orientation. The fact that the customer can also dance, for example, is not of interest in this context. Such an ability is not required for withdrawing money from an ATM.

As an object-oriented developer, you must therefore identify and describe objects relevant to the task at hand. The description of objects consists of relevant properties and skills. When you know what you need, you need to express the description of the objects in an object-oriented programming language such as C ++. The practical implementation in C ++ will be shown below.

The big advantage of object orientation is that you as a developer hardly have to provide any abstraction work. The path from intellectual problem solving to software is extremely short. While the assembler programmer has to concentrate on entering cryptic characters and the basic programmer has to visualize the flow of information in the program, the C ++ programmer simply uses the same objects in the code as in his head. Object-oriented programming therefore takes a big step towards the person, the programmer, and does not expect the programmer to enter the problem solution into the computer in a form that is largely based on the hardware architecture. In object orientation, it becomes possible for the first time for the developer to tell the computer that he wants to use this and that object. Once this has happened, it only works with the objects and does not care about the hardware dependency.

In order for the computer to be able to execute object-oriented programs, it must know exactly what the objects used in the program look like, what properties and capabilities they have. So you have to describe an object before you can use it. An object description is called a class in object orientation. A class is nothing more than the description of an object; in other words, a plan that defines which properties and capabilities the object should have.

While a class is just an object description, an object is, so to speak, a class that has come to life. A synonym for object is instance. Objects and instances are based on a class that they describe. Objects and instances have the properties and capabilities that have been defined in the class on which they are based.

You can easily imagine the difference between classes and objects using the following example. To build a house you first have to hire an architect to draw up a floor plan. The rooms, the location of windows and doors, sockets and so on are drawn into this plan. This plan completely describes the house after its completion.

However, just because you now have a plan of the house, it is far from being built. You cannot move in yet. The house has to be built first. Once this has been done and the construction workers have worked properly, the house corresponds exactly to the architect's drawing.

In object orientation, the architect's plan is the class, the built house is the object or instance. Just as you can use the floor plan to build more houses that all look identical, you can create multiple objects based on a class. As with houses, they are independent and separate objects, but they all look the same and have the same properties and capabilities.

You can also think of the relationship between classes and objects as follows: A class is a species or genus, and an object is a specific specimen of the species. Bees have a black and yellow striped body and the ability to fly. However, you will always be stung by a very specific bee. The BMW 316ti has a nominal output of 85 kW and accelerates from 0 to 100 km / h in 10.9 seconds. The 316ti BMW that is in your garage is an object of this class.

As an object-oriented programmer, you must always proceed as follows: First you create the class, then, based on the class, you create the object or objects you need. Without a class, i.e. without an object description, you cannot logically create an object.

The great thing about object orientation is that you can take objects from reality into your program. Instead of struggling with the hardware and playing the game by the rules of the computer, you simply work within the software with the same objects that are floating around in your head when solving problems.

Object orientation is a milestone compared to procedural programming. You may have already suspected it: In practice, however, it is not as simple as it all sounds. Even if object orientation solves many problems, it also creates new ones. As an object-oriented programmer, you face various problems: Which objects do I actually need to solve a problem? And which properties and methods do I actually need in an object in order to be able to use it meaningfully?

If you take another look at the software for the ATM: Are the customer and the bank really enough as objects? Or shouldn't additional objects like user interface, amount of money, account balance, money card and so on be used? This could make the customer and bank objects a little smaller by storing information in other objects. As the objects become clearer, the number of objects in the program grows overall, which at some point also becomes confusing.

While the customer does not need a property hair color, we had given him a property PIN. What other properties are important? Account balance, overdraft limit, expiry date of the card?

Working out the necessary objects and defining properties and skills can sometimes be extremely difficult. Several solutions can also be found, for which it is difficult to tell at the beginning which is the best. Working out the right objects, properties and skills and constructing the relationships in order to ultimately arrive at a meaningful program has created its own software industry. Programs that help developers create and maintain useful object models are especially important in larger project projects and can cost four-digit amounts.

In addition to the decisive advantage of depicting objects, object orientation has other strengths.

  • Perfect classes encapsulate data. This means that other classes can never directly access their own data. The interaction between objects based on classes does not take place via data access, but via access to capabilities. In our example, the customer calls up the ability to reduce the account balance of the Bank class instead of recalculating the account balance himself. That is the sole responsibility of the Bank class, and no other class should mess with its data. The object-oriented programming language Smalltalk forces the developer to create perfect objects in which all data is encapsulated because direct data access is not supported. In C ++, the programmer himself decides with the help of so-called access attributes whether or not to pursue the concept of data encapsulation.

  • Classes pass on properties and abilities to other classes. Inheritance can be used to create class hierarchies in which each class inherits from a different class and one or more parent classes are at the top of the class hierarchy. Inheritance has the advantage that classes become interchangeable because they have a common interface if they descend from the same parent class. In contrast to Java, C ++ supports multiple inheritance: A class can have more than one parent class and thus inherit multiple interfaces. In Chapter 3, Inheritance learn more about inheritance.

  • The programming language C ++ is not a 100% object-oriented programming language. You can also create C ++ programs that do not have a single class or object. You can override the rules of object orientation more or less at will. If something doesn't suit you, as it is intended in the object orientation, then most likely you don't have to do it in C ++ either. The Smalltalk programming language is much more rigorous here: you either stick to the rules or you change the programming language.

The extremely high flexibility of C ++ is probably the most important reason why this programming language has the largest market share and the greatest popularity among object-oriented languages. In C ++ you can, but do not have to, use all language features that are available for object-oriented development. This easily leads to confusion for C ++ beginners: Everything seems to be somehow optional and to work differently. Only practice, practice, practice helps here. The more programs you create in C ++, the faster you will recognize the advantages and disadvantages of the various approaches. As with all programming languages, experience is the most important thing in C ++.

1.3 Develop classes

Keywords and their meanings

As you already know, before an object can be created, a class must first be developed. Whether you program the class yourself or whether it was developed by someone else and you take it from the official C ++ standard, for example, does not matter - the main thing is that it is there.

In C ++, class definitions are usually packed in header files. For the sake of clarity, these files are usually given the same name as the class. For example, you can assume that there is a class in a header file and in a class. Whenever you want to create objects based on the class or class, simply add the header file to the source code file using the preprocessor command - and you can use the class to create an object based on it.

But what does a class definition look like? They know that a class defines traits and abilities. But how do you define that in C ++?

#include class customer {public: void PIN_eingeben (); private: std :: string PIN; };

What you see above is a class definition. Class definitions either begin with the keyword or. You will learn the exact difference between these two keywords later. The name of the class is given after the keyword. So the above class is called. The name of the class is followed by two curly braces between which the definition of the class is located. Don't forget to put a semicolon behind the closed curly braces - otherwise the compiler will complain.

The above class has a property and an ability called. In object-oriented terminology, one actually speaks of a property. However, skills are called methods.

From a technical point of view, a property is nothing more than a variable. It also doesn't matter whether the variable has an intrinsic data type or not. A variable that is defined within the curly braces of a class is called a property.

Technically, methods are nothing more than functions. Functions that are defined within a class are called methods. In this way, object-oriented programmers can also clearly state what they mean: a free-standing function or a function that is defined in a class.

If you look at the class definition above, you notice that the method definition is not complete. After all, only the method header is given. What the method should actually do when it is called is nowhere written. The class is therefore not yet sufficiently defined and cannot be used as above.

The implementation of methods is usually separated from the class definition. When a class is named, it is usually defined in a file. The method definitions are then usually in a file. In this way, class and files can be assigned quickly.

#include "customer.h" void customer :: PIN_eingeben () {}

The content of the file to complete the class could look like above. The class defines a single method. The method head must be specified followed by two curly brackets - in the same way as if you were to define a free-standing function. The only difference: Since it is a method that is always assigned to a class, you have to put the class name followed by the access operator in front of the method name. If you don't, it would be a freestanding role that isn't assigned to the class. That would still not complete the class.

Instead of separating the implementation of a method from the class in which the method is declared, you can also write the following.

#include class customer {public: void PIN_eingeben () {} private: std :: string PIN; };

Now the method is defined directly within the class and no longer just declared as before.

There is a minimal difference between methods that are only declared in a class and fully defined in a class. Methods whose implementation lies within a class are called inline methods. When an inline method is called, the code is not jumped to, but the compiler copies the code of the method to the places in the executable file at which the method is used. Inline methods trade storage space for speed: no jumps are necessary to execute code. The same code is present several times in the executable file, so that the memory requirement of the application increases.

You can create inline methods even if the implementation of a method is outside the class. You then have to put the keyword in front of the method declaration in the class.

#include class customer {public: inline void PIN_eingeben (); private: std :: string PIN; };

The method is only declared in the class and not defined.Still, the compiler will copy the method's code to all of the places in the executable where the method is called - at least in theory. In practice, compilers see inline methods more as recommendations than as mandatory specifications. The reason is that compilers can usually better judge how to optimize code, whether or not inline methods are used.

In practice, the class definition and the method definition are usually always placed in separate files. Even for inline methods, the keyword is used rather than completely defining the method within the class. The advantage of this division is that you can read the properties and methods from a class without having to worry about the implementation of the methods. You usually don't care about the implementation if you want to call methods on an object. The implementation is the task of the class. You just need to know what properties and methods the class provides in order to work with it. In this case, a class definition is a kind of documentation for programmers that provides information about which interface is available.

1.4 Create objects

Bring classes to life

When you have defined a class, you have taken the first step. Now the second step is to access the class and create an object based on the class.

Creating objects is extremely easy. These are simply variables whose data type is a class. That is the definition of an object. So to create an object, proceed as you always do when creating a variable. You first specify the data type and then the name of the variable, in this case the name of the object.

#include "customer.h" customer k;

To be able to create an object of the data type, you must of course first make the data type known. When you have defined the class in the header file, simply add it to your current source code file using the preprocessor command. In the example above, a variable is defined which, strictly speaking, represents an object, of the data type of the class.

In the class you indicated that there was a method. So your property has the ability to enter a PIN. How do you access this capability of your object from within C ++?

Properties and methods of objects are accessed using the access operator. So to call the method for your object, enter the following line.

k.PIN_eingeben ();

Ultimately, this line is nothing more than the call of a function - just not a free-standing function, but one that is defined within the data type on which the object for which you are calling the function is based. The object is based on the class, and that class has a method called whose parameter list is empty. The above method call is accordingly completely correct and would be translated by the compiler without complaint.

A few sections earlier you had learned about another access operator, namely to be able to specify in method definitions which class a method actually belongs to. So that you don't get confused: is the access operator for classes, the access operator for objects.

1.5 Access Rights

Access allowed or not

You know that you can use the access operator to access properties and methods of an object. Even so, the compiler would not translate the following line of code.

k.PIN = "Abc";

Although the class has a property, you cannot access that property. Namely, the property is private.

The C ++ programming language supports two access attributes: and. Properties and methods that are specified after may be accessed from outside the class. Properties and methods that are specified after may not be accessed from outside the class. Private properties and methods are therefore intended for internal use in the class. C ++ supports a third access attribute, which is only important in connection with inheritance and will therefore only be presented in a later chapter.

Do you remember that there are two keywords available for a class definition in C ++? The one keyword that is used in the vast majority of cases, you've already come to know - it is. Instead of defining a class with, you can also use the keyword. The only difference between and: In a class defined with, properties and methods are by default private, in a class defined with, properties and methods are public by default. After you can use the access attributes to define the type of access in a class at any time, you can define classes in different ways.

class example {int property1; int property2; public: void method1 (); void method2 (); };

Above named class defines two private properties and two public methods. If you want to define the class instead of using, write it as follows.

struct example {void method1 (); void method2 (); private: int property1; int property2; };

Both class definitions are the same. The compiler always generates the same code. How you define your classes is therefore irrelevant. It has become common practice to use normally. You should only use it if you want to document that your class consists mainly of public properties and methods and that other classes are therefore given extensive access.

You can use the access attributes and multiple times in a class definition. However, you should refrain from doing this and combine properties and methods that are subject to the same access mechanism in a block, as this increases the overview.

1.6 Practical example

That's how it's done

In this section, the classes and, which are repeatedly mentioned as examples in this chapter, are completed and used in a small application. This application simulates an ATM from which you can withdraw money.

The customer no longer only has to be able to enter a PIN, he also has to be able to insert his cash card into the machine and select an amount. The class is therefore expanded to look like this.

#include class customer {public: void money card_insert (); void enter_pin (); void amount_select (); private: std :: string PIN; };

As usual, the methods are implemented in a different file. The method is now also given a more meaningful method body, since it has so far not contained any statements and therefore nothing would have happened if it had been called.

The method can of course only simulate such a process. You most likely don't have a card reader plugged into your computer. The programming of card readers is also extremely complicated, since you have to program very close to the hardware, in complete contrast to object orientation. Our method simulates the process by simply entering a username.

#include "customer.h" #include #include void customer :: geldkarte_einschieben () {std :: string username; std :: cout << "Please insert your card into the machine:" << std :: flush; std :: cin >> username; } void customer :: enter_pin () {std :: cout << "Enter your PIN:" << std :: flush; std :: cin >> PIN; } void customer :: amount_choose () {int amount; std :: cout << "Enter how much money you want to withdraw:" << std :: flush; std :: cin >> amount; }

In each of the three methods, the standard input and output are accessed, so the header file must be integrated. The method creates an object of the type. Therefore, the header file must also be included.

All three methods output a text on the standard output and expect input from the user. Take a close look at the method. Data is read from the standard input and stored in a variable that is not defined in the method.

The compiler still doesn't complain. is a property of the class and is defined there. Any method of a class can access properties in a class at any time. In this case, the input of the user is saved in a property and not in a local variable.

By the way: the property is a private property. Access attributes such as and only restrict access to properties and methods to other classes. A method in a class can basically access all properties and methods, regardless of the access attributes with which they are protected. Access attributes only restrict external access.

The advantage of properties is that they have a larger scope than local variables. The property exists as long as the object based on the class. If the user has entered a PIN and the method has ended, the user's input is still saved in the property. This is the case with the methods and not the case: There, user inputs are saved in local variables, which are deleted from the memory after the method has ended. Their scope only extends over the methods and no further. The methods and must be reworked later when it is clear how the class and its methods work with the class.

The class is therefore defined in the next step. The class must manage data on the account so that, on the one hand, it can be checked whether the customer's access to the account at the ATM is OK, and, on the other hand, it can be prevented that the customer can withdraw an infinite amount of money. The first step is therefore to define the class as follows.

#include class bank {private: std :: string username; std :: string PIN; int account balance; };

What skills does the bank need to be given? She must check whether the user name entered by the customer and the PIN match and whether access is guaranteed. It must also reduce the account balance when withdrawing cash and, if necessary, prevent the payment if the account is overdrawn. The class is therefore expanded as follows.

#include class bank {public: bool access_check (std :: string username, std :: string pin); bool money_drawal (int amount); private: std :: string username; std :: string PIN; int account balance; };

The class receives two methods and. Both methods return a truth value that indicates whether the access is OK or whether the money could be withdrawn. In order to be able to check access, two values ​​are transferred to the method when it is called - namely the user name and the PIN that the user entered. A parameter of the type is passed to the method that specifies the amount that the customer would like to withdraw.

What is still missing is a way to initialize the properties of the class. This is why the class is given a method that must be called at the very beginning of the program and defines the values ​​with which the properties, and are pre-assigned.

#include class bank {public: void init (std :: string username, std :: string pin, int account balance); bool access_checking (std :: string user name, std :: string pin); bool money_drawal (int amount); private: std :: string username; std :: string PIN; int account balance; };

Now the implementation of the methods is still missing.

#include "bank.h" void bank :: init (std :: string username, std :: string pin, int account balance) {username = username; PIN = pin; Account balance = account balance; } bool bank :: check_ access (std :: string username, std :: string pin) {if (username == username && PIN == pin) {return true; } return false; } bool bank :: money_draw (int amount) {if (account balance> = amount) {account balance - = amount; return true; } return false; }

The method only sets the properties to the values ​​that are passed as parameters. The method compares the user name and the PIN passed as parameters with the properties of the object and returns or. The method first checks that the amount the customer wants to withdraw does not exceed the current account balance. If this is not the case, the account balance will be recalculated and returned - otherwise.

The class is now ready. We now have to turn back to the class and complete it or add access to the bank. The class has to be rebuilt a little for this. The input of the user name, which simulates the cash card, must be saved in a property in the class. Otherwise the bank cannot check the access in the method if the username entered is not permanently saved anywhere.

The method should also return whether the bank allows access or not. If access is not permitted, the user has to remove his card and insert it again. The user name must therefore be re-entered in the program. It must not be that the customer enters any PIN, the bank does not allow access, and the customer can still withdraw money. The method should also return whether the payout was successful or not.

The definition of the class changes minimally. Only a new property is added and the return value of the methods and is adapted.

#include class customer {public: void money card_insert (); bool PIN_eingeben (); bool amount_select (); private: std :: string username; std :: string PIN; };

The implementation of the methods of the class is interfered with in more depth.

#include "customer.h" #include "bank.h" #include bank b; void kunde :: geldkarte_einschieben () {std :: cout << "Please insert your card into the machine:" << std :: flush; std :: cin >> username; } bool kunde :: PIN_eingeben () {std :: cout << "Enter your PIN:" << std :: flush; std :: cin >> PIN; return b.Access_check (user name, PIN); } bool customer :: amount_choose () {int amount; std :: cout << "Enter how much money you want to withdraw:" << std :: flush; std :: cin >> amount; return b.money_drawal (amount); }

First of all, note that a global object of the type is created in this file. For this purpose, the header file is also included to make the class known.

The method no longer saves the user name in a local variable, but in a property. In the method, this user name is passed on to the method of the object together with the PIN. The return value of this method is also the return value of the method.

The object is also accessed in the method. The amount of money entered by the user that is to be withdrawn is transferred to the method. The return value of this method is at the same time the return value of the method.

The only thing missing is the function to start the program. The function looks like this.

#include "customer.h" #include "bank.h" #include extern bank b; int main () {customer k; b.init ("boris", "1234", 1000); for (;;) {k.geldkarte_einschieben (); if (k.PIN_eingeben () == true) {if (k.amt_waehlen () == true) {std :: cout << "The desired amount has been withdrawn." << std :: endl; }} else {std :: cout << "The PIN is wrong." << std :: endl; }}}

An object of the type is created in the function. The object is then initialized by calling the method. Notice how the object is accessed. The keyword is made known in front of the function. This means that an object can be accessed within this file that is created in another file. Look at this: An object is created in the file that defines the methods of the class. This object is now accessed in the function in order to initialize it. If you omitted the keyword, you would create a new object named. The compiler would then not translate the code because there would be two objects with the same name in the same scope. You must therefore specify.

After the object has been initialized, an endless loop is started. When you start the C ++ program, you can only use the key combination Ctrl+C. abort. Since an ATM is usually not shut down or shut down, the infinite loop is fine in this case.

The object is accessed in the endless loop. The three methods that are defined for this object are called one after the other.For the methods and, however, the return value is checked. This is because the program recognizes whether access to the bank account is permitted and whether the amount entered could be withdrawn. If an incorrect PIN is entered, the customer is not even asked to choose an amount. If the PIN is correct and the customer tries to withdraw more money than is in the account, the debit will not take place. In this case, the ATM does not display a corresponding confirmation of the debiting process.

The program is now ready. You can start it up and try it out. Enter boris as the user name and 1234 as the PIN to access the bank account. From there you can withdraw a total of 1000 euros. These are the values ​​with which the bank was initialized in.

1.7 Exercises

Practice creates masters

You can purchase the solutions to all of the exercises in this book as a ZIP file.

  1. Extend the practical example so that the customer can choose between the currencies euros and dollars after entering the correct PIN. Assume that the bank always manages account balances in euros. For the sake of simplicity, you can calculate with a conversion rate of 2 to 1 from euros to dollars.

    In order for the customer to be able to choose a currency, you have to give them an appropriate skill. That means you have to define a new method in the class that you call after entering the correct PIN. You need the currency that the customer has chosen in the method. Because in this method you transfer an amount in euros to the bank - after all, the bank settles everything in euros. You must therefore save the currency as a property in the class so that you can also access it in the method. An enumeration, for example, can be used as the data type for the new property.

  2. Extend the practical example from exercise 1 so that after entering the correct PIN, the customer should choose between a cash withdrawal and an account balance display. Regardless of which option he chooses, he must then log into the ATM again in order to be able to choose another option. Show the current account balance in the previously selected currency.

    Choosing for an option is a new skill that the customer must possess. You need a new method again, which you have to define for the class. If the customer has decided to display the account balance, you have to access a new method of the class, which has to be defined and which displays the account balance on the screen. You will find that the class does not even know the current account balance - only the bank knows it. You must therefore give the class a new method that can return the current account balance to the class.

  3. For security reasons, communication between customer and bank can no longer take place unencrypted. In detail, the user name and PIN may no longer be passed on from the class to the class without security precautions.

    Create a new class that implements the methods and. The method has no return value and expects a variable of the type as the only parameter. The method has a return value of the type and does not expect any parameters.

    The method of the class can now only accept parameters of the type. Before the class calls this method of the class, it must create objects of the type that store the information to be sent to the bank in the objects, and then pass the objects to the method as parameters. The method of the class reads the information in the objects passed as parameters by calling the method and decrypting the information.

    In order not to complicate the task unnecessarily, it is not necessary to actually implement encryption methods in the class.

    Go ahead, step by step: Start by creating the class. Then change the method. Finally, expand the method so that the correct parameters are passed to the method.

Copyright © 2001-2010 Boris Schäling