C++.TXT - doc included with MUD++ package. --- Tiny Introduction to C++ Furey <mec@duracef.shout.net> Fusion <msmith@hom.net> Fri 24 Mar 1995 === My experience When I learned C, I already knew Basic and Fortran. I read a 20-page handout from my local computer center and later I read Appendix A of Kernighan and Ritchie's _The C Programming Language_. That's all! Then I coded a lot and read other people's code. C is a small language and lots of people have learned it informally this way. I found C++ a much larger and more complex language than C. Partially, C++ does much more. And partially, it has to be backwards-compatible with C and with C-compatible linkers, so it has some ugly features. It took me about a year of full-time use to feel completely comfortable in C++. I alternated writing programs with reading books. I recommend this as a way to learn anything: practise some; read some. Keep reading even after you are writing code full time. I didn't understood C++ until after I read a Smalltalk manual. If you already know an OO language, you will have an advantage. If you -don't- already know C, you have a lot of work cut out for you! === Books I can't recommend an introductory book, but Stanley Lippmann's book has a good reputation. After I'd been hacking for a while I found some books that straightened me out and improved my coding practises a lot. These are not good 'first books' but they are all good 'second books': Cline, _C++ FAQs_ Meyers, _Effective C++_ Stroustrup, _The C++ Programming Language_ Both Cline's book and Meyer's book are broken into many small sections, so you can absorb it a little at a time. For an advanced book I recommend: Stroustrup, _The Design and Evolution of C++_ Books cost money and take time to read. Here's how I view it: I have twenty-four hours per day, same as everyone else. When I read a -good- C++ book, I get a lot of value per hour for each hour I spend reading it, and I save a lot of time in the long run. I found comp.lang.c++ a waste of time for learning the language. === Levels of C++ Usage There are three distinct levels of C++ features: (1) A Better C -- use only a few new features such as 'new' and 'delete'. If you can write C you can write at this level immediately. Most valuable features: 'new' and 'delete'; function overloading; inline functions. (2) Abstract Data Types -- use classes, but without inheritance. I wrote C++ like this for more than six months. Most valuable features: constructors; destructors; private members. You should think a lot about 'encapsulation' and 'programming by contract' at this stage. (3) Inheritance -- full use of the language. Once I figured out single inheritance, I moved to multiple inheritance and virtual inheritance quickly. At this stage, you should think about 'interface versus implementation' a lot. Also, I find C++ a confusing and ugly language at this stage. I browsed other books on Sather, Eiffel, and CLOS and found them very helpful. I recommend staying at each stage for a little while before moving on to the next. === Projects When I started learning C++ I wrote a couple of classes simply for experience: a string class and an array template class. I recommend doing this. Another good project class is an unlimited-length integer class, if you're into that. === Introduction for C coders A few C++ code examples. Fusion <msmith@hom.net> Stardate 1995 (sometime in the early morning) === A simple 'hello' The form of a C++ main is almost identical to a C program. The only thing you must do to make use of C++ output libraries is to include <iostream.h> where you would normally include <stdio.h> This is not required however. You may feel more comfortable in the early going using the stdio printf/scanf stuff but I would not recommend it. This is a simple jump and it is best to go ahead an make it or don't make it at all. // This is a C++ line comment. // -Fusion #include <iostream.h> void main() { cout << "This is all there is to it!" << endl; cout << " This " << "is " << "also " << "legal\n"; int Num = 1; cout << "Num = " << Num << endl; } Notice the use of the '<<' operator. We don't think of cout as a function call in C++. Rather it is a stream object. To send objects to cout you must use the insertion operator '<<'. Notice objects sent to cout can be stacked as in a stream. Also the old way of newline "\n" is also used as an alternative to the iostream flag 'endl'. The stream object is intelligent enough to convert data types to output format. So to output the integer Num we just stack it in there. No need to use the printf ( "%d", Num ) method. Notice also that unlike C, we can declare int Num anywhere before we use it, not just at the top of a code block. === I want some input! #include<iostream.h> void main() { cout << "Enter an integer :"; int Num; cin >> Num; cout << "You entered " << Num << endl; } Input with the standard iostream objects is done the same way except we use the 'cin' object and use the extraction operator '>>' instead of the insertion operator '<<'. Notice also that we dont have to tell cin what kind of datatype Num is for format. The compiler resolves this at compile time. More specifically the iostream and related classes have overloaded operators for each datatype. In this way you can redefine cout to output your user defined datatypes. === Whats an Object? C++ is based on a concept that your professor tried to teach you in school. This is encapsulation and user-defined data types to conceptually group data. In C this is done with a struct. The limitation with procedural languages is there is no real support for code reuse and abstraction. Abstraction is the practice of building in conceptual levels where each level is designed and debugged incrementally. Much like building a clock, where you construct the gears first then build on top of them. The end user doesn't have to know how the inner workings are designed to use it. This method is very helpful in engineering large projects. For some good theory (notice I didn't say code) you might want to grab Grady Booch's Object Oriented Design (Benjamin/Cummings Publishing). Say that you wanted a data type called Clock that kept hours, minutes, and seconds. In C you would do this: typedef struct { int hours; int minutes; int seconds; } Clock; Then, if you wanted to set the time to zero you would write a function called Reset() : void Reset( Clock *clock ) { clock->hours = clock->minute = clock->seconds = 0; } Then maybe to keep track of time you need a Tick() function: void Tick( Clock *clock ) { clock->seconds++; if( clock->seconds > 59 ) { clock->minutes++; clock->seconds = 0; if( clock->minutes > 59 ) { clock->hours++; clock->minutes = 0; } } } void main() { Clock clock; Reset( &clock ); for(;;) { Tick( &clock ); } } This code is fine but take a look at how the concept is centered on the function, not the object it works on. In real life the clock ticks itself so no outside force has to manually keep track of seconds and minutes. C++ lets us model this very closely. Take a look at the corresponding implementation of Clock in C++ below an compare to the C example. class Clock { private: int hours; int minutes; int seconds; public: Clock() : hours(0), minutes(0), seconds(0) // initializers for class data { // The initializers are better done the above way instead // of put here and using = sign. This way the initialization // is done as part of the image for the object. } void Tick( Clock * ); // prototype }; // the :: is the scope resolution operator, saying this function // is really in the scope of the Clock class even though the definition // is not physically there. void Clock::Tick() { clock->seconds++; if( clock->seconds > 59 ) { clock->minutes++; clock->seconds = 0; if( clock->minutes > 59 ) { clock->hours++; clock->minutes = 0; } } } void main() { Clock clock; for(;;) { clock.Tick(); } } The concept is much cleaner once you get used to it. Notice we didn't have to write a Reset() function in the class. This is because of another great C++ feature called the constructor. The constructor is really a function that is called automatically when the object instance is created. A constructor has no return type (not even void) and is not explicitly callable as is a function. Every time an instance of clock is created the members of the class are initialized to 0. This is very helpful because in big projects in a procedural language you have to worry about initializing structure members in any given scope of use. With C++ you can be assured that the constructor is called and forget about it. Constructors have the same name as the class definition. Another nice C++ feature is the ability to overload functions. In this way we could write more than one constructor. The only difference in the definition is the arguments or return type. The constructor Clock() has no arguments so it is called the default constructor. If you do not define a default constructor the compiler will generate one but dont expect it to do anything for you. Say we wanted to initialize clock to a specific time WHEN we create it. To do this we just define another constructor that takes arguments. class Clock { ... public: Clock() { ... set all to 0 ... } Clock( int hrs, int min, int sec ) : hours(hrs), minutes(min), seconds(sec) { } ... }; void main() { Clock clock1, // call default constructor clock2(12,3,55); // calls constructor with args for(;;) { clock1.Tick(); clock2.Tick(); } } Here clock1 gets set to 0:0.0 and clock2 gets 12:03.55 The correct constructor gets called for each object. One thing to remember here is that a class is the same as a struct in that defining the class/struct does not create any variables, but simply makes the "template" for any variables. You must think of each object instance as having its own variables and its own member function Tick(). Of course behind the scenes there is only ONE copy of the function Tick() but for the concept you dont need to know this. To Be Continued I Hope.