1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 144 pps

6 54 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 29,55 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The interface for the MainObjectArrayPtr class from quantum\newquant.h Figure newquant.03 codelist/newquant.03 You will notice that this class has an embedded class called MainObjectArr

Trang 1

other attributes of the quantum file But what is the type of m_MOA, and how does

it give us access to the quantum file attributes?

To answer these questions, we're going to have to get into some fairly complex implementation and language issues We'll start this excursion with a look at the interface for the MainObjectArrayPtr class, shown in Figure newquant.03

The interface for the MainObjectArrayPtr class (from quantum\newquant.h) (Figure newquant.03)

codelist/newquant.03

You will notice that this class has an embedded class called

MainObjectArray defined within it, and that the embedded class has quite a few member functions You may also notice that the MainObjectArrayPtr class itself has only a few member functions, most of which are the standard

"structural" member functions the normal and default constructors, the

destructor, and the assignment operator One of the constructors is the conversion function that constructs a MainObjectArrayPtr object from a

QuantumFile pointer (used in the FlexArray Open function), and the others are the default constructor and copy constructor However, there is one member function that is anything but standard: operator-> Why would we want to redefine that operator, and what can a custom version of operator-> do?

All Hope Abandon, Ye Who Enter Here?

Before we get through with this question, we will have entered a realm of C++ where relatively few have trespassed I don't believe in adding complexity for the sake of complexity, so why would I use a feature of C++ that most C++

programmers have never dealt with?

Because we need this feature to improve the ease of use and reliability of programs using this quantum file access method implementation A little history lesson is appropriate here so you can see that I'm not speaking from a solely theoretical perspective

The first edition of this book included an implementation of the quantum file

access method written in C.13 It had many of the features that the current

implementation has, but it was much harder to use The main problem was that the user program had to deal with memory allocation issues, including remembering to

Trang 2

free memory for variables whose storage was assigned inside the quantum file code In addition, the syntax of a quantum file "array" was much less convenient than dealing with a built-in array It was obvious to me that resolving all of these issues so that the user could ignore the inner workings of the quantum file would greatly improve the usability of this algorithm

Unfortunately, this isn't possible in C; however, a major impetus behind the

creation of C++ was to make it possible for class library designers to provide such facilities Since the quantum file access method would benefit greatly from such an approach, I decided to rewrite it in C++

Rewriting History

Why am I using the word "rewrite", rather than "convert", "translate", or other euphemisms? Judging from the number of ads for "C/C++ programmers" I see in the newspapers, some employers have the notion that switching to C++ can be accomplished by changing source file extensions to ".cpp" and recompiling After removing some syntax errors revealed by the stricter type checking of the C++ compiler, the program compiles and runs as it did before What's so difficult about object-oriented programming? If you are one of these employers, or you have tried the above experiment yourself and now believe that you are a "C++ programmer", let me break the news to you gently: all you have accomplished is to switch to the

C subset of C++, which has nothing to do with object-oriented programming

Virtually none of the code or design from the original quantum file implementation has survived the transition to object orientation unscathed, despite the fact that, according to an expert on object-oriented design, that original C implementation was "object-oriented"!

However, my loss (if that's what it was) can be your gain: I am going to break a long-standing tradition of object-oriented design literature by disclosing not only the final design but also many of the missteps, errors, and difficulties that ensued from my original determination to tackle this rather complex project So, with no further ado, let's begin with an often neglected concept which is at the core of the implementation of this project: operator overloading

Warning: Overload!

One of the most powerful mechanisms for hiding the details of implementation from the class user in C++ is operator overloading, which means defining (or in some cases redefining) the semantics of one or more of the standard operators +,

Trang 3

-, =, and so forth, as they apply to class objects For better or worse, the

semantics of these operators cannot be changed as they apply to "intrinsic" data types, so the calculation 2+2 is always going to result in 4; this restriction is

probably necessary, as the potential confusion could be horrendous.14 A good

example of the most common type of use for this facility is the implementation of +, -, etc., for manipulating Complex class objects, following the rules of complex arithmetic The ability to provide this sort of intuitive operation to the number-crunching user is starting to make C++ (with the proper class libraries,

of course) a viable alternative to FORTRAN, long the dominant language for such users

Hello, Operator?

As usual, it's probably best to start with a relatively simple example: in this case, we'll look at an example of overloading operator-.15 Consider the program in Figure overload1

Overloading operator- (Figure overload1)

codelist/minus.00

As you can see, I've created a very simplified version of the dreaded Point

class, used in innumerable textbooks to represent a point on the Euclidean plane The result of running our sample program is 5, which is the distance between the Point (1,1) and the Point (4,5), calculated by the normal Euclidean

calculation:

Distance = sqrt(xdiff*xdiff + ydiff*ydiff)

where xdiff is the difference between the x coordinates of the two Points, and

ydiff is the difference between their y coordinates; sqrt, of course, represents

the square root function

The "magic" is in the definition of operator-, which is the syntax for redefining

an operator; in this case it's the subtraction operator When the compiler sees the expression x-y, it looks for a definition of operator- that is specified for

class Point, taking an argument which is also of class Point Since there is such a definition, the compiler generates a call to the code specified in that

definition Had there not been such a definition, a syntax error would have

Trang 4

resulted, since the compiler doesn't have any built-in knowledge of how to subtract two Points

The Mask of Arrow

Operator overloading doesn't have to be terribly complicated, as that example illustrates However, there's a trick to the overloading of operator-> When we overload other operators, such as our earlier example of operator-, our code takes over the implementation of the operator completely That is, the result of calling our operator is whatever we say it is; in the operator- example, it's the double result of the Euclidean distance formula However, this is not true with operator->; in that case alone, a different scheme is followed by the compiler Figure overload2 shows some code derived from an early version of the project How does the compiler interpret it?16

Dangerous operator-> overloading (Figure overload2)

codelist/danger.00

The line X->Get(1); will be compiled as follows:

1 Since X is not a pointer to any type, its class definition is examined for a definition of operator->

2 Since this definition is found, a call to that code is inserted in the function being compiled

3 Then the return value of the operator-> code is examined Since it is a

pointer type (BlockPtr *, to be exact), the compiler continues by generating code to call BlockPtr->Get(int) with this equal to the result returned by operator->, which is the same BlockPtr that we started with

Type-Safety First

So far, this is doing exactly what we wanted it to do However, there is one serious problem with this method of implementing operator->, which is illustrated by what happens when the line Y->Get(1); is compiled Unlike our previous

example, Y is a pointer (to a BlockPtr); therefore, the compiler doesn't look for

a definition of operator->, but merely generates code to call

Trang 5

BlockPtr->Get(int) with this equal to Y As a result, our overloaded operator is never called

Much the same problem will occur when the line X.Get(1); is compiled The compiler is happy to generate a call to BlockPtr.Get(int) with this being equal to the address of X; again, though, our custom operator-> code won't be executed

The reason for this problem is that the compiler stops looking for operator-> overloading whenever an actual pointer is found After all, if you already have a pointer in a place where a pointer is needed, you must have what you want!

Obviously, we're going to have to come up with a type-safe solution, so we can't accidentally use the wrong syntax and end up with a nasty bug.17 The solution is to have not one, but two classes involved in the virtual memory mechanism, an

"outer" (or handle) class and an "inner" (or body) class.18 The handle class has two primary functions: the initializing of a body class object and the

overloading of operator-> to return a pointer to that body class object,

which actually does the work Figure overload3 presents this solution

Type-safe operator-> overloading (Figure overload3)

codelist/safe.00

One interesting thing about this program is that the main program refers to the Get function in exactly the same way as it did before: in fact, the only difference

visible to the class user is that the compiler is now able to prevent him (and us) from compiling the incorrect references as we did before

However, there are some changes to the internals that deserve comment First of all, in the class definition, the previous BlockPtr class has been renamed to Block and made a nested class of a new BlockPtr class The reason for the renaming is to prevent unnecessary changes to the user's code; that was

successful, as noted above Another design decision whose justification is not quite

as obvious is the use of a nested class rather than a freestanding class Why is this appropriate?

Hidden Virtues

Since the purpose of the nested Block class is solely to add type safety, rather than to provide any visible functionality, nesting it inside the BlockPtr class

Trang 6

reduces "name space pollution" That is, if the user needs a Block class for some other purpose, its name won't conflict with this one Such potential conflicts are going to become more serious as the use of class libraries increases; we should do our part to "preserve the environment" when possible.19 The fact that the Block class is visible only to members of its enclosing class, BlockPtr, is responsible for the somewhat odd appearance of the member function declarations

in Figure overload3 For example, what are we to make of the declaration "char BlockPtr::Block::Get(int p_Index)"?

Of course, we C++ programmers are used to "qualified" function names, such as Block::Get But why do we need two qualifiers? Because the compiler knows the meaning of Block only in the context of BlockPtr; that's what prevents the global name pollution that would ensue if Block were declared outside of BlockPtr This means that we could, for example, have another class called Block nested inside

Ngày đăng: 06/07/2014, 03:20

TỪ KHÓA LIÊN QUAN