Effective and More Effective C++

所需积分/C币:27 2017-02-24 10:30:01 5.51MB PDF
收藏 收藏

Effective and More Effective C++ 英文版 PDF
Item 1. I swapped the order of Items 4 1 and 42, because that made it easier to present the revised material they contain. Finally, i reversed the direction of my inheritance arrows. They now follow the almost-universal convention of pointing from derived classes to base classes. This is the same convention I followed in my 1996 book, More effective c+t The sct of guidelines in this book is far from exhaustive, but coming up with good rulcs? oncs that arc applicable to almost all applications almost all the time is harder than it looks. Perhaps you know of additional guidelines, of more ways in which to program effectively in C++. If so, I would be delighted to hear about them. On the other hand you may feel that some of the Items in this book are inappropriate as general advice; that there is a better way to accomplish a task examined in the book; or that one or more of the technical discussions is unclcar, incomplete, or mislcading. i encourage you to let me know about thcsc things, too Donald Knuth has a long history of offering a small reward to people who notify him of errors in his books. The quest for a perfect book is laudable in any case, but in view of the number of bug-ridden C++ books that have been rushed to market, I feel especially strongly compelled to follow Knuth's example. Therefore, for each error in this book that is reported to me be it technical, grammatical, typographical or otherwise i will, in future printings, gladly add to the acknowledgments the name of the first person to bring that error to my attention Send your suggested guidelines, your comments, your criticisms, and? sigh? your bug reports to Scott Meyers c/o Publisher, Corporatc and Professional Publishing Addison Wesley longman, Inc. 1 Jacob Way Reading. Ma o1867USA Alternativelyyoumaysendelectronicmailtoec++@awl.com. I maintain a list of changes to this book since its first printing, including bug-fixes, clarifications, and technical updates. This list is available at the Effective C++ World Wide Web site. If you would like a copy of this list, but you lack access to the World wide web, please send a request to one of the addresses above, and i will see that the list is sent to you ° Scott Douglas meyers Stafford. Oregon July 1997 Back to dedication Continue to Acknowledgment You can find an overview of the research at the Effective c++ World wide Web site Return Dedication For Nancy, without whom nothing would be much worth doing Continue to preface Back to Introduction Continue to item 1: Prefer const and inline to #define Shifting from C to C++ Getting used to C++ takes a little while for everyone, but for grizzled C programmers, the process can be especially unnerving. Because C is effectively a subset of c-t, all the old c tricks continue to work, but many of them are no longer appropriate. To C++ programmers, for example, a pointer to a pointer looks a little funny Why we wonder, wasn't a reference to a pointer used instead C is a fairly simple language. All it really offers is macros, pointers, structs, arrays, and functions. No matter what the problem is, the solution will always boil down to macros pointers structs arrays and functions Not so in C+t. The macros, pointers, structs, arrays and functions are still there, of course, but so are private and protected members, function overloading, default parameters, constructors and destructors, user-defined operators. inline functions references friends templates. exceptions namespaces and more the design space is much richer in C++ than it is in C: there are just a lot more options to consider When faced with such a variety of choices, many C programmers hunker down and hold tight to what theyre used to. For the most part, that's no great sin, but some C habits run contrary to the spirit of C+t. Those are the ones that have simply got to go Back to Introduction Continue to Item 1: Prefer const and inline to #define. Back to Shifting from C to C+. Continue to item 2 Prefer <iostream to <stdio h> Item 1: Prefer const and inline to #define This Item might better be called"prefer the compiler to the preprocessor, " because tdefine is often treated as if it's not part of the language per se. That's one ofits problems. When you do something like this, +define ASPECT RATIo 1.653 the symbolic name ASPECT RaTIO may never be seen by compilers; it may be removed by the preprocessor before the source code ever gets to a compiler. As a result, the name AsPECt RaTIO may not get entered into the symbol table. This can be confusing if you get an error during compilation involving the use of the constant, because the error message may refer to 1.653, not ASPECT RATIO. If ASPECT RATIO was defined in a header filc you didnt write, you'd then have no idca where that 1.653 came from, and you'd probably waste timc tracking it down. This problem can also crop up in a symbolic debugger, because, again, the name you're programming with may not be in the symbol table The solution to this sorry scenario is simple and succinct. Instead of using a preprocessor macro, define a constant const double ASPECT RATIO= 1.653 This approach works like a charm. There are two special cases worth mentioning, however First, things can get a bit tricky when defining constant pointers. Because constant definitions are typically put in header files(where many diffcrent source files will include them), it's important that the pointer be declared const, usually in addition to what the pointer points to. To define a constant char -based string in a header file for cxamplc, you have to write const twice const char x const authorname =scott meyers For a discussion of the meanings and uses of const, especially in conjunction with pointers, see Item 21 Second, it's often convenient to define class-specific constants, and that calls for a slightly different tack. To limit the scope of a constant to a class, you must make it a member and to ensure there's at most one copy of the constant, you must make it a static member class Game Player private: static const int NUM TURNS =5 // constant declaration int scores [NUM TURNS] // use of constant Therc's a minor wrinkle, howcvcr, which is that what you scc above is a declaration for NUM TURNS, not a definition. You must still define static class members in an implementation file const int GamePlayer:: NUM TURNS i / mandatory definition; / goes in class impl. file There's no need to lose sleep worrying about this detail. If you forget the definition, your linker should remind you. Older compilcrs may not accept this syntax, bccausc it used to be illegal to provide an initial valuc for a static class member at its point of declaration. Furthermore, in-class initialization is allowed only for integral types (cg, ints, bools, chars, ctc ) and only for constants In cases wherc the above syntax can ' t bc uscd, you put the initial value at the point of definition: class Engineeringconstants i // this goes in the class private // header =ile static const double fudGe factor // this coes in the class implementation file const double engineeringConstants:: FUDGE FACTOR 1.35 This is all you need almost all the time the only exception is when you need the value of a class constant during compilation of the class, such as in the declaration of the array GamePlayer: scores above(where compilers insist on knowing the size of the array during compilation). Then the accepted way to compensate for compilers that(incorrectly) forbid the in-class specification of initial values for integral class constants is to use what is affectionately known as"the enum hack. "This technique takes advantage of the fact that the values of an enumerated type can be used where ints are expected, so game Player could just as well have been defined like class Game Player I pr⊥vate enum NUM TURNS =5 H //the enum hack"? makes / NUM TURNS a symbolic name // for int scores INUM TURNS / fine Unless you're dealing with compilers of primarily historical interest (i.e, those written before 1995), you shouldn' t have to use the enum hack. Still, it's worth knowing what it looks like, because it,'s not uncommon to encounter it in code dating back to those early simpler times Getting back to the preprocessor, another common(mis)use of the #define directive is using it to implement macros that look like functions but that don't incur the overhead of a function call. The canonical example is computing the maximum of two values #define max(a b)((a)>(b)?(a):(b) This little number has so many drawbacks, just thinking about them is painful. You're better off playing in the freeway during rush hour Whenever you write a macro like this, you havc to remember to parenthesize all the arguments when you write the macro body; otherwise you can run into trouble when somebody calls the macro with an expression. But even if you get that right, look at the weird things that can happen int a max(++a b) //a is incremented twice max(++a,b+10); // a is incremented once Here, what happens to a inside max depends on what it is being compared with Fortunately, you don 't need to put up with this nonsense. You can get all the efficiency of a macro plus all the predictable behavior and type-safety of a regular function by using an inline function( see Item 33) inline int max(int ar int b) return Now this isn't quite the same as the macro above, because this version of max can only be called with ints, but a template fixes that problem quite nicely templa ce<class T> inline const T& max(const T& ar const t& b) i return a b? a: b; I This template generates a whole family of functions, cach of which takes two objects convertible to the same type and returns a reference to(a constant version of) the greater of the two objects. Because you don 't know what the type t will be, you pass and return by reference for efficiency(see Item 22) By the way, before you consider writing templates for commonly useful functions like max, check the standard library (see Item 42)to see if they already exist. In the case of max, you'll be pleasantly surprised to find that you can rest on others' laurels: max is part of the standard c+t library Given the availability of consts and inlines, your need for the preprocessor is reduced, but it's not completely climinated. The day is far from ncar when you can abandon #include, and #ifdef#ifndef continuc to play important roles in controlling compilation. It's not yet time to retire the preprocessor, but you should definitely plan to start giving it longer and more frequent vacations Back to shifting from c to c++ Continue to item 2 Prefer <iostream> to <stdio h> Back to Item 1: Prefer const and inline to t define Continue to item 3: Prefer new and delete to malloc and free Item 2 Prefer <iostream> to <stdio. h Yes, theyre portable. Yes, they're efficient. Yes, you already know how to use them. Yes, yes, yes. But venerated though they are, the fact of the matter is that scanf and printf and all their ilk could use some improvement. In particular, they're not type-safe and theyre not extensible. Because type safety and extensibility are cornerstones of the C++ way of life, you might just as well resign yourself to them right now. Besides, the printf/scanf family of functions separate the variables to be read or written from the formatting information that controls the reads and writes, just like fortran does. It's time to bid the 195os a fond farewell Not surprisingly, these weaknesses of printf/scanf are the strengths of operator>> and operator<< int li Rational ri i/ r is a rational number cin >> i>> r: cout <s i <s r If this code is to compile, thcre must bc functions opcrator>> and opcrator<< that can work with an object of type Rational (possibly via implicit type conversion? see Item M5). If these functions are missing, it's an error (The versions for ints are standard. )Furthermore, compilers take care of figuring out which versions of the operators to call for different variables, so you needn' t worry about specifying that the first object to be read or written is an int and the second is a rational In addition, objects to be read are passed using the same syntactic form as are those to be written, so you don 't have to remember silly rules like you do for scanf, w here if you don' t already have a pointer, you have to be sure to take an address, but if you've already got a pointer, you have to be sure not to take an address. Let C++ compilers take care of those details. They have nothing better to do, and you do have better things to do. Finally note that built-in types like int are read and written in the same manner as user-defined types like Rational. Try that using scanf and printf! Here's how you mi ght write an output routine for a class representing rational numbers class Rational Rational(int numerator =0 int denominator =l)i private int n, / numerator and denominator friend ostream& operator<<(ostream& s, const Rational& r)i ostream& operator<<(ostream& s, corst Rational& r) s<<工.n<< return si This version of operator<< demonstrates some subtle(but important) points that are discussed elsew here in this book. For example, operators<< is not a member function(Item 19 explains why), and the rational object to be output is passed into operator<< as a reference-to-const rather than as an object( see Item 22). The corresponding input function, operator>>, would be declared and implemented in a similar manner Reluctant though I am to admit it, there are some situations in which it may make sense to fall back on the tried and true. First, some implementations of iostream operations are less efficient than the corresponding C stream operations, so it's possible( though unlikely see Item Ml6) that you have an application in which this makes a significant difference. Bear in mind, though, that this says nothing about iostreams in general, only about particular implementations; see Item M23. Second the iostream library was modified in some rather fundamcntal ways during thc coursc of its standardization(scc Item 42), so applications that must bc maximally portable may discover that different vendors support different approximations to the standard. Finally, because the classes of thc iostream library havc constructors and the functions in <stdio. h> do not, there arc rarc occasions involving the initialization order of static objects(see Item 4Z)when the standard c library may be more useful simply because you know that you can always call it with impunity The type safety and extensibility offered by the classes and functions in the iostream library are more useful than you might initially imagine, so don't throw them away just because you're used to <stdio. h>. After all, even after the transition you'll still have your memories Incidentally, that's no typo in the Item title; I really mean <iostream and not <iostream. h>. technically speaking, there is no such thing as <iostream.h>? the standardization commi ttee eliminated it in favor of iostream when they truncated the names of the other non-C standard header names. The reasons for their doing this are explained in Item 49, but what you really need to understand is that if (as is likely) your compilers support both <iostream> and <iostream. h>, the headers are subtly different. In particular, if you include Iostream>, you get the elements of the iostream library ensconced within the namespace std(see Item 28), but if you #include <iostream. h>, you get those same elements at global scope. Getting them at global scope can lead to name conflicts, precisely the kinds of name conflicts the use of namespaces is designed to prevent. Besides <iostream> is lcss to typc than <iostream.h>. For many pcoplc, that's reason enough to prefer it Back to Item I Prefer const and inline to define Continue to item 3: Prefer new and delete to malloc and free

试读 127P Effective and More Effective C++
立即下载 低至0.43元/次 身份认证VIP会员低至7折
Effective and More Effective C++ 27积分/C币 立即下载
Effective and More Effective C++第1页
Effective and More Effective C++第2页
Effective and More Effective C++第3页
Effective and More Effective C++第4页
Effective and More Effective C++第5页
Effective and More Effective C++第6页
Effective and More Effective C++第7页
Effective and More Effective C++第8页
Effective and More Effective C++第9页
Effective and More Effective C++第10页
Effective and More Effective C++第11页
Effective and More Effective C++第12页
Effective and More Effective C++第13页
Effective and More Effective C++第14页
Effective and More Effective C++第15页
Effective and More Effective C++第16页
Effective and More Effective C++第17页
Effective and More Effective C++第18页
Effective and More Effective C++第19页
Effective and More Effective C++第20页

试读结束, 可继续阅读

27积分/C币 立即下载 >