Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006)

.pdf
Скачиваний:
192
Добавлен:
12.08.2013
Размер:
3.18 Mб
Скачать

724 THE OBJECT-ORIENTED APPROACH

4.12Advantages of Object-Oriented Programming

A large part of the programming community has already embraced object-oriented programming as a better way to program. One of the main advantages is the robustness of the programs, a direct result of encapsulation. The changes carried out within an object class have no side effects on other parts of the program, and the internal details of an object class are well insulated from the outside world. This significantly simplifies the maintenance of programs. If in the future, the functionality of a class needs to be enhanced, the additional coding needed will be localised to the class itself and will not affect the functionality of unrelated classes. The changes may not even affect the public interface of the object itself. If we take a real-life example, drivers operate motorcars exactly the same way they did in the past. However, the fuel system has changed from carburisation to fuel injection. While the performance of the object is enhanced, the motorcar is driven exactly the same way through the public interface (the accelerator pedal).

Inheritance permits us to reuse the code over and over again. This reduces reprogramming time and the associated debugging time. It allows us to reduce our time-to-market and lower the cost of software development. The natural relationship between real-life objects and software objects makes it easier to understand the class structures. This is the strategy we used in this chapter to give you a good insight into object classes.

The most powerful and the most useful feature of object-oriented programming is associated with virtual functions and object hierarchies. Using virtual functions enables the program to select the correct function to operate on the objects that are specified at run time. This relieves the programmer from having to write lengthy code to cater for individual objects that may be specified at run time by the user of the program.

4.13Disadvantages of Object-Oriented Programming

In general there is reluctance among programmers who are familiar with procedural programming to embrace object-oriented programming. Object-oriented concepts are quite foreign and require some adjustment in thinking, especially so for novices.

Object-oriented programming is often not usually justified when programs are very small. Also, object-oriented programming may not be the best choice for programs requiring time-critical program execution. However, with the increasing speed of computers this is becoming a less significant issue. Operating systems that burden the computer are typically more of a concern than the object-oriented programs themselves.

4 THE OBJECT-ORIENTED APPROACH 73

4.14 Summary

In this chapter we used real-life examples to promote understanding of objectoriented concepts. We started by differentiating the two programming methods; procedural programming and object-oriented programming. Procedural programming exposes data and functions for inadvertent misuse and it can lead to unexpected side-effects and difficult debugging. Object-oriented programming imposes data hiding and protects data from inadvertent misuse by encapsulating data and functions together to form object classes. The public interface of an encapsulated object class has been explained using real-life examples.

A qualitative explanation was given to explain the abstract object classes and actual object classes. This has then been consolidated using object-oriented terminology to explain abstract classes and real classes. Also, inheritance has been exploited in an example object hierarchy to show how a class hierarchy can be developed.

The use of constructors and destructors has been briefly introduced and will be explained in greater detail in the coming chapters. Instantiation has a close association with constructors, and a given class may have any number of constructors.

The important concepts of polymorphism and virtual functions have been discussed in limited detail due to their relative complexity. They will be further explained and used extensively in Chapter 8. Finally, advantages and disadvantages of objectoriented programming have been discussed.

4.15 Bibliography

Meyer, B., Object Oriented Software Construction, Prentice Hall, 1988.

Firesmith, D.G., Object Oriented Requirements, Analysis and Logical Design, John Wiley, 1993.

Staugaard A. C. (Jr), Structured and Object Oriented Techniques, Prentice Hall, 1997.

Gray, N.A.B, Programming with Classes, John Wiley, 1994.

5

Object-Oriented

Programming

Inside this Chapter

ξ

ξ

ξ

ξ

Creating an object class.

Developing objects for ports.

Access attributes.

Developing the ParallelPort object class.

5.1 Introduction

Our aim in this chapter is to teach you how to develop object classes for use in C++ programs. The object-oriented concepts introduced in the previous chapter will be expanded upon and C++ syntax will be added to the class definitions. The object classes developed in this chapter will be used in the development of future programs that interact with various devices on the interface board through the parallel port of your PC.

We will start the chapter by developing a fundamental parallel port object type named ParallelPort that will be developed in three separate stages. Each stage of developement will give the ParallelPort object additional functionality, with the final class capable of data transfer to and from the computer using most features of the parallel port.

5.2 Naming Convention

In order to improve the readability of our programs, we will establish a naming convention to be used when assigning names to functions and other identifiers. As explained in Chapters 2 and 3, the parallel port of the PC occupies three consecutive addresses. In most cases, the hexadecimal values of these consecutive addresses are 0x378, 0x379 and 0x37A. The term BASE will be used to refer to the first of the three addresses which we call the base address (0x378 in this case). Table 5-1 summarises the naming convention.

Table 5-1 Naming convention for identifiers in programs.

 

Offset with respect to

Physical Address

Suffix for Identifiers

Base Address (BASE)

(most widely used)

Port0

0

0x378

Port1

1

0x379

Port2

2

0x37A

NOTE

The port addresses you will be using may not necessarily be 0x378, 0x379 and

0x37A. However, they will be three consecutive addresses. The object classes

we develop will have the flexibility to specify the BASE address that applies to

your particular case.

5 OBJECT-ORIENTED PROGRAMMING 77

According to the naming convention shown in Table 5-1, all member data and member functions ending with Port0 will use address BASE. For example, a function with the name WritePort0() writes data to the port at address BASE. Similarly, WritePort2() writes data to the port at address BASE+2.

5.3 Developing an Object Class

By the end of this chapter we will have developed a complete ParallelPort class that encompasses most functional aspects of the port. This will take place in three stages; in the first stage we will develop a class using the BASE address. This class will be expanded in two following stages to include the functionality of the BASE+1 address, and lastly the BASE+2 address.

ParallelPort class

ParallelPort class

ParallelPort class

(BASE, BASE+1 and

(BASE Address)

(BASE and BASE+1 Addresses)

BASE+2 Addresses)

 

 

 

 

 

 

class ParallelPort

 

 

class ParallelPort

 

class ParallelPort

{

 

 

{

 

{

.

 

 

.

 

.

.

 

 

.

 

.

.

 

 

.

 

.

.

 

 

.

 

.

}

 

 

.

 

.

 

 

 

.

 

.

Stage 1

 

.

 

.

 

}

 

.

 

 

 

 

 

.

 

 

 

 

 

.

 

 

 

Stage 2

.

 

 

 

 

 

}

 

 

 

 

 

Stage 3

Figure 5-1 Developing the ParallelPort Class.

The port at BASE address is the easiest to use and can send one byte of data at a time. Note that newer computers can both send and receive data through this port. We will only use the BASE address as an output port to maintain compatibility with older computers.

Designing an object class:

1.Select an appropriate name for the object class. It should be concise, yet descriptive enough to suit the purpose and content of the class.

2.Determine class member data (features or properties associated with the object).

3.Determine class member functions (uses of the object).

4.Use the appropriate access attributes to encapsulate the data and functions.

5.Establish constructor(s) and the destructor for the class.

78 5 OBJECT-ORIENTED PROGRAMMING

In the previous chapter, member data were identified as features or properties associated with the object. Member functions were identified as the uses of the object. If we use everyday language to describe a port at address BASE as an object class, it will read something like this:

“The port is at a certain address and can output one byte of data”

According to this description, the port is identified by an address. The object is used to output a byte of data to an external device using this port. Now that we have established the features and the uses, we can try to define the object class. We will encapsulate this member data and member function to form our fundamental object class ParallelPort.

5.3.1 Member Data

The ParallelPort object class we are developing must know the base address of the port in order to operate. This data needs to be stored in a data member that we have appropriately named BaseAddress. Most parallel port addresses will fall in the range of 0 to 0x3FF. An 8-bit number (0 to 0xFF) will be too small to store these values, and so a 16-bit number (0 to 0xFFFF) must be used. Therefore, we need to declare a data type of unsigned int to the data member BaseAddress so it can store the required range of possible port addresses:

unsigned int BaseAddress;

5.3.2 Member Functions

Since the ParallelPort class needs to be able to write a byte of data to the port at BASE address, a function named WritePort0() will be created for this purpose. One byte is represented by the data type unsigned char. The function only outputs data, so it does not need to return a value. This means its return value type should be void. The resulting function is:

void WritePort0(unsigned char data)

{

outportb(BaseAddress, data);

}

The function WritePort0()takes in one parameter, namely data of type unsigned char. The body of the function contains just one statement; it outputs the value of the parameter passed as data to the port at the address specified by the value of BaseAddress.

WritePort0() has a return value specified as void. In functions that do not return any value, the return value type must be specified as void. If the functions are to return a value, then there must be a return statement within the body of the function.

5 OBJECT-ORIENTED PROGRAMMING 79

5.3.3 Access Attributes

The access attributes control accessibility to the members of the class by functions anywhere else in the program. There are three different types of access attributes; private, protected, and public, described as follows.

private

Functions and data listed under the private access attribute can only be accessed by member functions of the same class. Other functions from elsewhere cannot modify or even see any of the private member data, nor can they call any private member functions. Importantly, if an access attribute is not specified for any of the members in a class definition, the access attribute defaults to be private.

protected

Functions and data listed under the protected access attribute can be accessed by the member functions of the class itself and member functions of all other classes derived using this class as the base class. Classes, which have no relationship to this class, cannot access the protected member data or protected member functions. Class derivation is further explained in Chapter 6.

public

Functions and data listed under the public access attribute can be accessed by any function regardless of its relationship to the class.

5.3.4 Defining a Class

The more attractive way to develop object classes that offers greater protection is to use class definitions. A class definition starts with the keyword class followed by the name given to the object type (in this case ParallelPort). It is entirely up to you to choose this identifier for the object type. It is also possible in C++ to define an object using aggregates of related data known as structures.

As shown in Figure 5-2, the body of the class definition starts at the first open brace ({) and it ends when the last close brace (}) is encountered. Remember to place a semicolon (;) after the close brace to complete the class definition.

There are two segments within the body of the class definition. The first segment relates to member data, and the second segment relates to member functions. Although the member data and member functions can be intermingled, it is good practice to keep them separate.

As mentioned earlier, if an access attribute is not specified, then it defaults to private. Therefore, the keyword private in the class definition is not essential. If it was dropped, the variable BaseAddress would still be private. However, it is good practice to include the keyword private to make the code more explicit.

80 5 OBJECT-ORIENTED PROGRAMMING

class ParallelPort

{

Member Data

 

Start of the body of the class definition

Class definition ends with last close brace

};

private:

unsigned int BaseAddress;

Member Function(s)

public:

void WritePort0(unsigned char data)

{

outportb(BaseAddress, data);

}

Must not forget semicolon!

Figure 5-2 Class definition.

The class has a default constructor and a default destructor provided by the compiler that are not visible. The constructor creates objects for use in a program and the destructor relinquishes objects from memory once the program no longer needs them.

ParallelPort Class

Private Member Data:

BaseAddress

Public Member Functions:

Interface to outside program

WritePort0( )

code (main function)

Constructors & Destructors:

Defaults provided by compiler (invisible)

Figure 5-3 Schematic of the ParallelPort Class.

5 OBJECT-ORIENTED PROGRAMMING 81

In the case of the object class ParallelPort, BaseAddress is a private data member. Therefore, it can only be accessed by the function WritePort0() belonging to this class. This function is declared to be public and as such can be called by any other function in your program. This provides an interface between the object and the outside world. If the function WritePort0() was declared private, it could not be called by any function outside the class (including the main() function). As a result the object of type ParallelPort could not be used (recall the sealed off car that no one can get in to drive!).

5.3.5 The Constructor

The purpose of a constructor is to create objects for use in a program. Simply because there is an object type definition, it does not mean that there is an actual object that resides in memory. For an object to hold data and execute functions, both data and functions must reside in memory. This occurs when the constructor is called. It creates an object and allocates memory to all its data members in a process known as instantiation. At the time of instantiating an object all statements in a constructor’s body will be executed. The programmer may code the constructor to suit the needs of the objects at the time of their creation.

Constructors always have the same name as the object type – in this case, ParallelPort. A constructor, although a function, never has a return value. This is a unique feature of constructors. They are one of only two types of functions in C++ which have no return value type, not even void. The second type of function with no return value is the destructor.

5.3.6 Default Constructor

The strict definition of the default constructor is a constructor that does not take any parameters (i.e. the pair of parentheses are empty). In the absence of a constructor provided by a programmer, the compiler will provide a constructor and that constructor is always a default constructor. The default constructor provided by the compiler has one main job, to allocate memory for all data members of the object. It will also call the default constructor of its base class if it has one – this occurs before the derived class constructor calls allocates memory for its own data members.

It is also possible for a programmer to provide a default constructor. The default constructor written by the programmer also takes no parameters, but can have some statements in its body. If the programmer provides a constructor, be it default or otherwise, the compiler will not provide a constructor. The programmer-supplied default constructor will also call the default constructor of its base class before executing its own duties.

The compiler also provides a special constructor named the copy constructor, and an overloaded assignment operator (the = sign). We will defer the discussion of copy constructors and overloaded assignment operators until Chapter 12.

82 5 OBJECT-ORIENTED PROGRAMMING

5.3.7 Overloading of Constructors

The term overloading is used to describe the situation when many functions exist under the same name but carry out different tasks. For the case of overloaded constructors, there is more than one constructor in a class definition, all having the same name (the name of the class), and as for all constructors, not having return value types. Any number of overloaded constructors are allowed in a class. Therefore, the only difference between the constructors should be in the number and types of parameters passed to each of them and the statements included in each of their bodies.

5.3.8 Destructors

The destructor serves the opposite purpose of the constructor. A constructor brings an object into life by creating it in memory. A destructor removes the object from memory, freeing the space. The name of the destructor must always be the name of the object class and preceeded by the tilde symbol (~). For example, the destructor for the ParallelPort class would be named ~ParallelPort(). The program developer can choose to include a destructor in the class definition. If the developer does not include a destructor, the compiler will generate a default destructor.

Unlike constructors, destructors are not explicitly called. They will be called automatically when a locally defined object ceases to exist or when the delete operator is used to delete the object from memory. For class hierarchies, the destructor of the derived class is executed before the destructor of its base class.

While there are no virtual constructors, destructors can be virtual functions. Virtual destructors will be described in detail in Section 8.5. We will now begin the development of the ParallelPort class in the three stages we mentioned at the start of Section 5.3 and as shown in Figure 5-1.

5.4 Parallel Port Class – Stage I

This first stage in the development of the ParallelPort class will produce a class having the simplest features of the three stages. This stage will only use the capabilities of the BASE address component of the port, being the ability to write a byte of data (8 bits, D0-D7 inclusive) to external devices.

Initially a default constructor will be used as part of the class (generated by the compiler). This design has some deficiencies discussed ahead. The class will be developed further to overcome these shortcomings.

5.4.1 Class Definition

As described earlier, WritePort0() is a public member function. Therefore, any function in the program can call this function. The WritePort0() function