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

Thinking in C plus plus(P17) pptx

50 410 0

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 50
Dung lượng 183,03 KB

Nội dung

780 Thinking in C++ www.BruceEckel.com much further. A complicated container-class library may cover all sorts of additional issues, including multithreading, persistence and garbage collection. Exercises Solutions to selected exercises can be found in the electronic document The Thinking in C++ Annotated Solution Guide , available for a small fee from www.BruceEckel.com. 1. Implement the inheritance hierarchy in the OShape diagram in this chapter. 2. Modify the result of Exercise 1 from Chapter 15 to use the Stack and iterator in TStack2.h instead of an array of Shape pointers. Add destructors to the class hierarchy so you can see that the Shape objects are destroyed when the Stack goes out of scope. 3. Modify TPStash.h so that the increment value used by inflate( ) can be changed throughout the lifetime of a particular container object. 4. Modify TPStash.h so that the increment value used by inflate( ) automatically resizes itself to reduce the number of times it needs to be called. For example, each time it is called it could double the increment value for use in the next call. Demonstrate this functionality by reporting whenever an inflate( ) is called, and write test code in main( ) . 5. Templatize the fibonacci( ) function on the type of value that it produces (so it can produce long , float , etc. instead of just int ). 6. Using the Standard C++ Library vector as an underlying implementation, create a Set template class that accepts only one of each type of object that you put into it. Make a nested iterator class that supports the “end sentinel” concept in this chapter. Write test code for your Set in main( ) , and then substitute the Standard C++ Library set template to verify that the behavior is correct. 16: Introduction to Templates 781 7. Modify AutoCounter.h so that it can be used as a member object inside any class whose creation and destruction you want to trace. Add a string member to hold the name of the class. Test this tool inside a class of your own. 8. Create a version of OwnerStack.h that uses a Standard C++ Library vector as its underlying implementation. You may need to look up some of the member functions of vector in order to do this (or just look at the <vector> header file). 9. Modify ValueStack.h so that it dynamically expands as you push( ) more objects and it runs out of space. Change ValueStackTest.cpp to test the new functionality. 10. Repeat Exercise 9 but use a Standard C++ Library vector as the internal implementation of the ValueStack . Notice how much easier this is. 11. Modify ValueStackTest.cpp so that it uses a Standard C++ Library vector instead of a Stack in main( ) . Notice the run-time behavior: Does the vector automatically create a bunch of default objects when it is created? 12. Modify TStack2.h so that it uses a Standard C++ Library vector as its underlying implementation. Make sure that you don’t change the interface, so that TStack2Test.cpp works unchanged. 13. Repeat Exercise 12 using a Standard C++ Library stack instead of a vector (you may need to look up information about the stack , or hunt through the <stack> header file). 14. Modify TPStash2.h so that it uses a Standard C++ Library vector as its underlying implementation. Make sure that you don’t change the interface, so that TPStash2Test.cpp works unchanged. 15. In IterIntStack.cpp , modify IntStackIter to give it an “end sentinel” constructor, and add operator== and operator!= . In main( ) , use an iterator to move through 782 Thinking in C++ www.BruceEckel.com the elements of the container until you reach the end sentinel. 16. Using TStack2.h , TPStash2.h , and Shape.h , instantiate Stack and PStash containers for Shape* , fill them each with an assortment of upcast Shape pointers, then use iterators to move through each container and call draw( ) for each object. 17. Templatize the Int class in TPStash2Test.cpp so that it holds any type of object (feel free to change the name of the class to something more appropriate). 18. Templatize the IntArray class in IostreamOperatorOverloading.cpp from Chapter 12, templatizing both the type of object that is contained and the size of the internal array. 19. Turn ObjContainer in NestedSmartPointer.cpp from Chapter 12 into a template. Test it with two different classes. 20. Modify C15:OStack.h and C15:OStackTest.cpp by templatizing class Stack so that it automatically multiply inherits from the contained class and from Object . The generated Stack should accept and produce only pointers of the contained type. 21. Repeat Exercise 20 using vector instead of Stack . 22. Inherit a class StringVector from vector<void*> and redefine the push_back( ) and operator[] member functions to accept and produce only string* (and perform the proper casting). Now create a template that will automatically make a container class to do the same thing for pointers to any type. This technique is often used to reduce code bloat from too many template instantiations. 23. In TPStash2.h , add and test an operator- to PStash::iterator , following the logic of operator+ . 24. In Drawing.cpp , add and test a function template to call erase( ) member functions. 16: Introduction to Templates 783 25. (Advanced) Modify the Stack class in TStack2.h to allow full granularity of ownership: Add a flag to each link indicating whether that link owns the object it points to, and support this information in the push( ) function and destructor. Add member functions to read and change the ownership for each link. 26. (Advanced) Modify PointerToMemberOperator.cpp from Chapter 12 so that the FunctionObject and operator->* are templatized to work with any return type (for operator->* , you’ll have to use member templates , described in Volume 2). Add and test support for zero, one and two arguments in Dog member functions. 785 A: Coding Style This appendix is not about indenting and placement of parentheses and curly braces, although that will be mentioned. It is about the general guidelines used in this book for organizing the code listings. 786 Thinking in C++ www.BruceEckel.com Although many of these issues have been introduced throughout the book, this appendix appears at the end so it can be assumed that every topic is fair game, and if you don’t understand something you can look it up in the appropriate section. All the decisions about coding style in this book have been deliberately considered and made, sometimes over a period of years. Of course, everyone has their reasons for organizing code the way they do, and I’m just trying to tell you how I arrived at mine and the constraints and environmental factors that brought me to those decisions. General In the text of this book, identifiers (function, variable, and class names) are set in bold . Most keywords will also be set in bold, except for those keywords that are used so much that the bolding can become tedious, such as “class” and “virtual.” I use a particular coding style for the examples in this book. It was developed over a number of years, and was partially inspired by Bjarne Stroustrup’s style in his original The C++ Programming Language . 1 The subject of formatting style is good for hours of hot debate, so I’ll just say I’m not trying to dictate correct style via my examples; I have my own motivation for using the style that I do. Because C++ is a free-form programming language, you can continue to use whatever style you’re comfortable with. That said, I will note that it is important to have a consistent formatting style within a project. If you search the Internet, you will find a number of tools that can be used to reformat all the code in your project to achieve this valuable consistency. 1 Ibid. A: Coding Style 787 The programs in this book are files that are automatically extracted from the text of the book, which allows them to be tested to ensure that they work correctly. Thus, the code files printed in the book should all work without compile-time errors when compiled with an implementation that conforms to Standard C++ (note that not all compilers support all language features). The errors that should cause compile-time error messages are commented out with the comment //! so they can be easily discovered and tested using automatic means. Errors discovered and reported to the author will appear first in the electronic version of the book (at www.BruceEckel.com ) and later in updates of the book. One of the standards in this book is that all programs will compile and link without errors (although they will sometimes cause warnings). To this end, some of the programs, which demonstrate only a coding example and don’t represent stand-alone programs, will have empty main( ) functions, like this int main() {} This allows the linker to complete without an error. The standard for main( ) is to return an int , but Standard C++ states that if there is no return statement inside main( ) , the compiler will automatically generate code to return 0 . This option (no return statement in main( ) ) will be used in this book (some compilers may still generate warnings for this, but those are not compliant with Standard C++). File names In C, it has been traditional to name header files (containing declarations) with an extension of .h and implementation files (that cause storage to be allocated and code to be generated) with an extension of .c . C++ went through an evolution. It was first developed on Unix, where the operating system was aware of upper and lower case in file names. The original file names were 788 Thinking in C++ www.BruceEckel.com simply capitalized versions of the C extensions: .H and .C . This of course didn’t work for operating systems that didn’t distinguish upper and lower case, such as DOS. DOS C++ vendors used extensions of hxx and cxx for header files and implementation files, respectively, or hpp and cpp . Later, someone figured out that the only reason you needed a different extension for a file was so the compiler could determine whether to compile it as a C or C++ file. Because the compiler never compiled header files directly, only the implementation file extension needed to be changed. The custom, across virtually all systems, has now become to use cpp for implementation files and h for header files. Note that when including Standard C++ header files, the option of having no file name extension is used, i.e.: #include <iostream> . Begin and end comment tags A very important issue with this book is that all code that you see in the book must be verified to be correct (with at least one compiler). This is accomplished by automatically extracting the files from the book. To facilitate this, all code listings that are meant to be compiled (as opposed to code fragments, of which there are few) have comment tags at the beginning and end. These tags are used by the code-extraction tool ExtractCode.cpp in Volume 2 of this book (which you can find on the Web site www.BruceEckel.com ) to pull each code listing out of the plain-ASCII text version of this book. The end-listing tag simply tells ExtractCode.cpp that it’s the end of the listing, but the begin-listing tag is followed by information about what subdirectory the file belongs in (generally organized by chapters, so a file that belongs in Chapter 8 would have a tag of C08 ), followed by a colon and the name of the listing file. Because ExtractCode.cpp also creates a makefile for each subdirectory, information about how a program is made and the command-line used to test it is also incorporated into the listings. If A: Coding Style 789 a program is stand-alone (it doesn’t need to be linked with anything else) it has no extra information. This is also true for header files. However, if it doesn’t contain a main( ) and is meant to be linked with something else, then it has an {O} after the file name. If this listing is meant to be the main program but needs to be linked with other components, there’s a separate line that begins with //{L} and continues with all the files that need to be linked (without extensions, since those can vary from platform to platform). You can find examples throughout the book. If a file should be extracted but the begin- and end-tags should not be included in the extracted file (for example, if it’s a file of test data) then the begin-tag is immediately followed by a ‘ ! ’. Parentheses, braces, and indentation You may notice the formatting style in this book is different from many traditional C styles. Of course, everyone thinks their own style is the most rational. However, the style used here has a simple logic behind it, which will be presented here mixed in with ideas on why some of the other styles developed. The formatting style is motivated by one thing: presentation, both in print and in live seminars. You may feel your needs are different because you don’t make a lot of presentations. However, working code is read much more than it is written, and so it should be easy for the reader to perceive. My two most important criteria are “scannability” (how easy it is for the reader to grasp the meaning of a single line) and the number of lines that can fit on a page. This latter may sound funny, but when you are giving a live presentation, it’s very distracting for the audience if the presenter must shuffle back and forth between slides, and a few wasted lines can cause this. [...]... place the opening parenthesis for a multi-line definition: int func(int a) { int b = a + 1; return b * 2; } and for a single-line definition that is often used for inlines: int func(int a) { return (a + 1) * 2; } Similarly, for a class: 790 Thinking in C+ + www.BruceEckel.com class Thing; is a class name declaration, and class Thing { is a class definition You can tell by looking at the single line in. .. and encapsulate its hard parts into other objects, etc 4 Don’t automatically rewrite all your existing C code in C+ + unless you need to significantly change its functionality (that is, don’t fix it if it isn’t broken) Recompiling C in C+ + is a valuable activity because it may reveal hidden bugs 798 Thinking in C+ + www.BruceEckel.com However, taking C code that works fine and rewriting it in C+ + may... Don’t use private inheritance Although it’s in the language and seems to have occasional functionality, it introduces 804 Thinking in C+ + www.BruceEckel.com significant ambiguities when combined with run-time type identification Create a private member object instead of using private inheritance 33 If two classes are associated with each other in some functional way (such as containers and iterators),... normal typing system and is a potential error spot Since the explicit casts divide C s one-cast-does-all into classes of well-marked casts, anyone debugging and maintaining the code can easily find all the places where logical errors are most likely to happen 810 Thinking in C+ + www.BruceEckel.com 61 For a program to be robust, each component must be robust Use all the tools provided by C+ +: access control,... less confusing for the reader 58 Guarantee that initialization occurs in all aspects of your code Perform all member initialization in the constructor initializer list, even built -in types (using pseudo-constructor calls) Using the constructor initializer list is often more efficient when initializing subobjects; otherwise the default constructor is called, and you end up calling other member functions... style is that capitalization has meaning – you can see from the first letter whether you’re talking about a class or an object/method This is especially useful when static class members are accessed 794 Thinking in C+ + www.BruceEckel.com Order of header inclusion Headers are included in order from “the most specific to the most general.” That is, any header files in the local directory are included first,... Standard C+ + exception hierarchy and nested as public classes within the class that throws the exceptions The person catching the exceptions can then catch the specific types of exceptions, followed by the base type If you add new derived exceptions, existing client code will still catch the exception through the base type 52 Throw exceptions by value and catch exceptions by reference Let the exception-handling... derived-class functions Not only do you save code space, you provide for easy propagation of changes You can use an inline function for efficiency Sometimes the discovery of this common code will add valuable functionality to your interface 1 Explained to me by Andrew Koenig B: Programming Guidelines 801 18 Watch for switch statements or chained if-else clauses This is typically an indicator of type-check... efficient to restrict an existing class in its subclass than it would be to restructure the hierarchy so your new class fits in where it should, above the old class 802 Thinking in C+ + www.BruceEckel.com 22 Don’t extend fundamental functionality by subclassing If an interface element is essential to a class it should be in the base class, not added during derivation If you’re adding member functions... want a copyconstructor or operator= declare them as private Remember , that if you create any constructor, it prevents the default constructor from being synthesized 37 If your class contains pointers, you must create the copyconstructor, operator= and destructor for the class to work , properly 38 When you write a copy-constructor for a derived class, remember to call the base-class copy-constructor . 780 Thinking in C+ + www.BruceEckel.com much further. A complicated container-class library may cover all sorts of additional issues, including multithreading, persistence and garbage collection A: Coding Style 791 class Thing; is a class name declaration, and class Thing { is a class definition. You can tell by looking at the single line in all cases whether it’s a declaration. policy for the way lines are broken up, so they can be easily viewed. As long as something is part of a single definition, 794 Thinking in C+ + www.BruceEckel.com argument list, etc., continuation

Ngày đăng: 05/07/2014, 19:20

TỪ KHÓA LIÊN QUAN