Teach Yourself Visual C++ 5 in 21 Days

Appendix B: Learning C/C++ Quickly (Part 2)

Objectives:

The second chapter for this term will be Appendix B. The objectives important to this chapter are:

  • creating a structure
  • creating classes
  • creating functions in classes
  • constructors and deconstructors
  • overloading functions
  • C++ rules about variables
  • default parameters for functions
Concepts:

Appendix B begins by discussing structures. You may recall that a structure is like an array, in the sense that it takes up a defined amount of memory space. It is like a database record, in that all members of the structure need not be of the same type (while all members of an array must be of the same type). In fact, members of a structure are usually of different types, else you wouldn't need to make a structure to hold them.

The example on page 711 shows a simple structure with two members. It is declared with the keyword struct, named MYSTRUCTURE, and defined as having two members: a character array, size 100, and an integer. Note, to facilitate handling the character array, the author included the string header in his program.

The code noted above creates a kind of structure for this program. This is like making a new type, in that the name of this type of structure is now used to create an instance of this type of structure. which the author called MyStructure. If you are following my analogy of records in a database, another way of illustrating the concepts might go like this:

	#include 
	#include 
	
	struct RECORDSHAPE
	{
		char sName[100];
		int  iAge;
	};

	void main()
	{
		RECORDSHAPE Record1;
		strcpy(Record1.sName, "Steve");
		Record1.iAge=44;
	}

I defined the structure, ending the definition with semicolon. I put declared that an instance of this structure exists and called it Record1. I put data in the members of Record1 by using its name, the dot operator, and the name of one of its members, using a simple assignment operator for the integer and the strcpy function for the string.

The creation of multiple structures is covered through page 715, where the author takes up the topic of classes. A class is something new, something we have not discussed before. It is like a structure, in that it must be declared and defined to have a certain shape and size (although you will see later that we can cheat and add to it, in a way). A class has members, like a structure. What is different is that while members of a class can be data holders, members of a class can also be functions.

Declaring a class is illustrated on page 716. The author names it:

	class Circle

In other words, let there be a class called Circle. He then starts to define it:

	
	{
	public:
		Circle();
		void SetRadius(void);
		void GetRadius(void);
		~Circle();
	private:
		void CalculateArea(void);
		int radius;
		int color;
	};

This looks weird. The public and private sections are meant to show you that there are some parts of the class that will interface with the world and some that will not. Members that are public may be called or accessed by code in the program. Members that are private may only be called or accessed by code in the class itself.

There are four public members declared in this example, the second and third being standard looking function prototypes. These functions will be defined very soon in the program. The first and fourth members are odd. The first is the prototype for the constructor function for the class. Essentially, it is a requirement that it be there, shaped like this, in order for the class to work. It is what allows the computer to create an instance of the class. Note that type keywords were not used with it. A keyword is never used for the return type, but variables and keywords may be used in the parentheses. (I'll show you in a few lines.)

The fourth member of the class is the prototype for the deconstructor function for the class. You should be aware that C and C++ are memory efficient languages. Think of the deconstructor function as being necessary to clean up memory after we are done using an instance of a class. Type keywords are not used with the deconstructor function prototype, either. Note that the constructor function of a class is the first public member declared and the deconstructor function for the class is the last public member declared. This would be true even if this class had data members as well as member functions in the public section. (Yes, I know, the syntax for this makes no sense. Remember, the poor creatures who created this thought in UNIX...) The constructor function has the same name as the class, and the deconstructor function has the same name, preceded by a tilde.

The author, having bewildered you with the above, then switches gears and confuses you with a change in syntax for his code. As he likes to precede the name of an integer variable with an i, a character variable with a c, and so on , he tells us to precede the name of a class with a capital C. You don't have to do this, but it is consistent with his style. Likewise, when he include data members, he precedes their names with m_, regardless of their type. (Well, there goes the consistency. It could be worse. I have seen people preface a Visual Basic variable with several characters, to note its type, scope, location, etc. You start to wonder if they are being paid by the keypress...)

On page 722, the code changes to look like this:

	
	class CCircle
	{
	public:
		CCircle( int r ); //Constructor
		void SetRadius( int r );
		void DisplayArea(void);
		~CCircle();  //Deconstructor
	private:
		float CalculateArea(void);
		int m_Radius;
		int m_Color;
	};

Since we changed the name of the class (added the prefixed C), we had to change the names of the constructor and deconstructor functions as well. This time the constructor is meant to receive a variable to tell it how big the circle we are making will be. The return type is still not mentioned and should not be. The full version of the code appears on pages 720 and 721. Note that the first thing the program does after the class declaration is to define the class functions. His constructor function does not do much, just assigns the value of the integer passed to it to the m_Radius member.

// The Constructor function
CCircle::CCircle(int r)
{
	// set the radius
	m_Radius = r;
}

He does not use the dot operator because it happens internally, and the function assumes that the named variable (m_Radius) is a member of the class. The unusual use of the double colon tells the compiler that this function (named to the right of the double colon) is a member of the named class (named to the left of the double colon). Without this notation, the compiler might think that this was simply an external function. available to any other function in the program.

Defining deconstructor functions is easy. You don't put anything in them, you just let C++ worry about it. It is required, however, that this worthless looking code be in the program.

// The Destructor function
CCircle::~CCircle()
{
}

The next two pages illustrate creating an instance of this class. The program code creates an instance called MyCircle and passes the value 10 to it. The class code receives the value 10 and places it in the m_Radius member of MyCircle. Then the program calls the DisplayArea member of MyCircle. This is allowed because this is a public member function. DisplayArea calls CalculateArea, which it is allowed to do because it happens internally in the class. If the program code had tried to call the CalculateArea member directly, it would have failed because that member is private to the class. This may seem silly, since all the code is in one program anyway.

This distinction is important when you consider the version of the program starting on page 733. Here, the author creates a header file containing the definition of the CCircle class. Including this header allows a new C++ program to use the class, without rewriting the whole thing over again. (Aren't headers wonderful?) Now, the source code for the class is not readily available to the programmer. This is more like our usual programming habits, taking advantage of existing work. ("If I have seen farther than others, it is because I have stood on the shoulders of giants." -- Isaac Newton) This is one of the major features of object oriented programming. If we create a useful object, save it in a header so it can be reused in other programs.

The next major topic of this chapter is overloading functions. Overloading is to assign a second definition to a function, allowing a new use of the function. The author illustrates this by overloading the SetRadius function. He distinguishes between them on page 736 by prototyping it/them once with one parameter, and once with two parameters. He them defines each function. In reality, he could as easily defined two separate functions. The author says this approach is easier, but he glosses over the fact that the programmer now has to be aware of the overloaded function, that there are two versions of it and how to use each, as opposed to there being two functions and knowing how to use each. His comment on page 741 is essentially that the overloading approach makes for cleaner code in the main function. I agree, but it also makes for more confusion and less sanity.

On page 742, the author discusses the difference between declaring variables in C and C++. In C, all variables must be declared before any executed line of code in written. In C++, we are allowed to throw in a new variable declaration anywhere in the program, so long as it is before that variable is used. This makes it easier to toss a new variable in the program at the last minute.

On page 743, default parameters are discussed. In C++, you can specify what parameters a function should receive if it is passed no parameters or is passed an insufficient number of parameters. In the example, the function MyFunction is prototyped like this:

	void MyFunction(int a = 10,
		int b = 20,
		int c = 30,
		int d = 40);

This would normally be on one line, but I use the author's notation for visibility on this web page. When this function is called and passed no parameters, the four defaults are used. If two parameters are passed, they take the place of the first two defaults, if one is passed it takes the place of the first default. Note: the default values are specified in the prototype, not the definition. Also note that you can override a default by passing a value, but you can't override just one default out of sequence. That is, if you want to pass a value for b, in the example, you have to pass a value for a as well. If you want to pass a value for c, you have to pass a value for a and b as well.