A Review of Classes

Introduction

In the previous lesson, we introduced data types that are usually referred to as primitive. Each of these data types is used to create an object that can hold a single value, such as the number of bedrooms of a house, the type of house, etc. Here are examples of such variables:

using namespace System;

int main()
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	Byte Stories;
	double Bathrooms;
	int YearBuilt;
	double Value;

	return 0;
}

Notice that, in this example, some or all of the variables could be used to create a single object.

Practical LearningPractical Learning: Introducing Classes

  1. To start a new program, launch Microsoft Visual C++ 2008
  2. On the main menu, click File -> New -> Project...
  3. On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
  4. In the Name box, replace the string with RealEstate4 and click OK
  5. To create a source file, on the main menu, click Project -> Add New Item...
  6. In the Templates list, click Source File (.cpp)
  7. In the New box, type Exercise and click Add
  8. In the empty file, type:
    using namespace System;
    
    int main()
    {
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        return 0;
    }
  9. To execute the application, on the main menu, click Debug -> Start Without Debugging
  10. Click Yes

Creating a Class

The C++ language allows you to use one, or a group of more than one, type of values to create what would be referred to as a composite type. This type is created as a class. As introduced in Lesson 1, to create a class, start with either the struct or the class keyword, followed by a name and ending with a semi-colon. The name of the class follows the same rules we have been applying to the variables so far. Here is an example:

struct House;

Or

class House;

We we will start the names of our classes with C:

struct CHouse;

Or

class CHouse;

After creating a CHouse class like this, it doesn't (yet) have any functionality. You have simply indicated that you want a data type that is itself one or a group of values. To create it, you list the parts of a class between an opening curly bracket "{" and a closing curly bracket "}". Everything between these brackets is part of the class and such a section is referred to as the body of the class. It would be created as follows:

struct CHouse{ };

Or

class CHouse{ };

In the body of the class, you can list the items that compose it. Each item is called a member of the class. Each item is identified by its type and a name. For example, if you want to create a CHouse class that is simply known for its value, you can define a member value of double type. Such a class would look like this:

struct CHouse{ double Value; };

Or

class CHouse{ double Value; };

Most objects are made of various parts. Listing all parts on a single line could be cumbersome. Therefore, you can span the body of a class on various lines. An example would be:

struct CHouse {
// Body of the class
};

or

struc CHouse
{
// Body of the class
};

Or

class CHouse {
// Body of the class
};

or

class CHouse
{
// Body of the class
};

In the body of the class, you can then list its members. Each member is created as a variable, declaring it using any of the techniques we used in the previous lesson. Here are examples:

struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	Byte Stories;
	double Bathrooms;
	int YearBuilt;
	double Value;
};
class CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	Byte Stories;
	double Bathrooms;
	int YearBuilt;
	double Value;
};

If two variables are of the same type, you can declare them with one data type as done for variable declarations in the previous lesson. Here is an example:

struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms, YearBuilt;
	Byte Stories;
	double Bathrooms, Value;
};
class CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms, YearBuilt;
	Byte Stories;
	double Bathrooms, Value;
};

To indicate that a member variable belongs to the class, another way you can declare it is by preceding its name with the name of the class followed by the :: operator. Here are example:

struct CHouse
{
	__wchar_t CHouse::TypeOfHome;
	int CHouse::Bedrooms;
	Byte CHouse::Stories;
	double CHouse::Bathrooms;
	int CHouse::YearBuilt;
	double CHouse::Value;
};
class CHouse
{
	__wchar_t TypeOfHome;
	int CHouse::Bedrooms, YearBuilt;
	Byte Stories;
	double Bathrooms, CHouse::Value;
};
 

Practical LearningPractical Learning: Creating a Class

  1. On the main menu, click Project -> Add New Item...
  2. In the Templates list, click Header File (.h)
  3. In the New box, type Property and click Add
  4. In the empty file, type the following:
    #pragma once
    
    class CHouse
    {
        long PropertyNumber;
        __wchar_t PropertyType;
        unsigned Stories;
        unsigned Bedrooms;
        float Bathrooms;
        unsigned YearBuilt;
        double PropertyValue;
    };
  5. Save the file

Value Types

 

Introduction

The data types we studied in the previous lesson are each used to declare a variable that holds a (single) value. As mentioned in the previous lesson, each of these variables is also created in the stack memory. After declaring the variable, you can initialize it with a value of your choice. When the variable has been initialized, the value is "put" in the memory where the variable resides. A data type used to declare such a variable is called a value type. In the same way, when you create a class, by default, it is a value type. To re-enforce the fact that the class is a value type, you can precede its struct or class keyword with the value keyword. Here is an example:

House
value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};
value class CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

When introducing assemblies in Lesson 1, we saw that you could control the "visibility" of a class outside of its assembly, using the private or public keyword. To apply this to a value class, you can precede the value keyword with private or public:

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};
public value class CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};
 

Practical LearningPractical Learning: Creating a Value Class

  1. To make the class a value type, change the file as follows:
    #pragma once
    
    public value struct CHouse
    {
        long PropertyNumber;
        __wchar_t PropertyType;
        unsigned Stories;
        unsigned Bedrooms;
        float Bathrooms;
        unsigned YearBuilt;
        double PropertyValue;
    };
  2. Save the file

Creating a Value Type

In the previous lesson and above, we saw how you could declare a variable of a primitive type. This is the same way you declare a variable of a value: the name of the class, followed by a name for the variable, followed by a semi-colon. Here is an example:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse home;

	return 0;
}

As done with the primitive types, you can declare two or more class variables with one type. Here are examples:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse home;
	CHouse singleFamily, townhouse;

	home.Stories;
	return 0;
}
House

When you declare a variable of a class, we say that you have created an instance of the class, or that you have instantiated the class. The word instance here means that the object is alive or has been made alive in your program.

After declaring a value type, you can access the members of its class. This is done using the member access operator ".". To access a member, type the name of the declared variable, followed by a period, followed by the name of the member you want to access. For example, to access the YearBuilt member of the above home variable you would write:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse home;

	home.YearBuilt;
	return 0;
}

Using this syntax, you can display the value of a class member:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse home;

	Console::WriteLine(home.YearBuilt);
	return 0;
}

You can also use the cout class or the printf_s() function to display the values of the object's members.

Techniques of Initializing an Object

There are various techniques used to initialize an object: initializing individual members or initializing the object as a whole. To initialize a member of an object, access it and assign it an appropriate value. Here is an example:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse singleFamily;

	singleFamily.Bathrooms = 2.5;
	singleFamily.Stories = 3;
	singleFamily.Value = 524885;
	singleFamily.YearBuilt = 1962;
	singleFamily.TypeOfHome = L'S';
	singleFamily.Bedrooms = 5;

	Console::Write("Type of Home:        ");
	Console::WriteLine(singleFamily.TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(singleFamily.Bedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(singleFamily.Bathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(singleFamily.Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(singleFamily.YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(singleFamily.Value);

	return 0;
}

This would produce:

Type of Home:        S
Number of Bedrooms:  5
Number of Bathrooms: 2.5
Number of Stories:   3
Year Built:          1962
Monetary Value:      524885
Press any key to continue . . .

Notice that we initialized the members in any order of our choice. You can also initialize an object as a variable. This time, type the name of the variable followed by the assignment operator, followed by the desired values of the variables listed between an opening and a closing curly brackets. Each value is separated with a comma. The first rule you must observe is that the list of variables must follow the order of the declared members of the class. The second rule you must observe is that none of the members of the class can be another class. Here is an example:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse singleFamily = { L'S', 5, 2.5, 3, 1962, 524885 };

	Console::Write("Type of Home:        ");
	Console::WriteLine(singleFamily.TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(singleFamily.Bedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(singleFamily.Bathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(singleFamily.Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(singleFamily.YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(singleFamily.Value);

	return 0;
}

Like any other variable, before using an object, you must first declare it. Although the usual technique consists of declaring an object where needed, C/ C++ supports another technique. You can declare a variable next to the class. To do this, type the name of the class between the closing curly bracket and the semi-colon. Here is an example:

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
} townhouse;

In this case, the townhouse variable is a valid instance of the object and gives access to the members of the object. This means that you can simply initialize any of its members as you see fit. Here is an example:

using namespace System;

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
} townhouse;

int main()
{
	townhouse.YearBuilt = 1986;
	townhouse.Bathrooms = 1.5;
	townhouse.Stories = 3;
	townhouse.Value = 348255;
	townhouse.Bedrooms = 3;
	townhouse.TypeOfHome = L'T';

	Console::Write("Type of Home:        ");
	Console::WriteLine(townhouse.TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(townhouse.Bedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(townhouse.Bathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(townhouse.Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(townhouse.YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(townhouse.Value);

	return 0;
}

This would produce:

Type of Home:        T
Number of Bedrooms:  3
Number of Bathrooms: 1.5
Number of Stories:   3
Year Built:          1986
Monetary Value:      348255
Press any key to continue . . .

Just like you would declare more than one variable, you can declare many instances of a class when creating the object. Here is an example:

public value struct CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
} singleFamily, townhouse, comdominium;

Practical LearningPractical Learning: Initializing an Object

  1. To use the class as a type, change the Exercise.cpp file as follows:
    #include "Property.h"
    
    using namespace System;
    
    int main()
    {
        CHouse townhouse;
    
        townhouse.PropertyNumber = 872735;
        townhouse.YearBuilt = 1986;
        townhouse.Bathrooms = 1.5;
        townhouse.Stories = 3;
        townhouse.MarketValue = 348255;
        townhouse.Bedrooms = 3;
        townhouse.PropertyType = L'T';
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        Console::Write("Property #:          ");
        Console::WriteLine(townhouse.PropertyNumber);
        Console::Write("Type of Home:        ");
        Console::WriteLine(townhouse.PropertyType);
        Console::Write("Number of Bedrooms:  ");
        Console::WriteLine(townhouse.Bedrooms);
        Console::Write("Number of Bathrooms: ");
        Console::WriteLine(townhouse.Bathrooms);
        Console::Write("Number of Stories:   ");
        Console::WriteLine(townhouse.Stories);
        Console::Write("Year Built:          ");
        Console::WriteLine(townhouse.YearBuilt);
        Console::Write("Monetary Value:      ");
        Console::WriteLine(townhouse.MarketValue);
    
        return 0;
    }
  2. Execute the application to see the result
    =//= Altair Realty =//=
    -=- Properties Inventory -=-
    Property #:          872735
    Type of Home:        T
    Number of Bedrooms:  3
    Number of Bathrooms: 1.5
    Number of Stories:   3
    Year Built:          1986
    Monetary Value:      348255
    Press any key to continue . . .
  3. Close the DOS window

Class Members Levels of Access

To exercise a good level of control over your class, you "hide" some members and "expose" some others. This is done by setting different levels of access for the member of the class. To do this, you will define what members are public and which ones are private. The members that are public are preceded with the public keyword followed by a colon. The others are considered private. Still, to specify that a member is private, you can precede it with private:. Here are examples:

public value struct CHouse
{
private:
	__wchar_t TypeOfHome;
	int Bedrooms;
public:
	double Bathrooms;
private:
	Byte Stories;
	int YearBuilt;
	double Value;
private:
};

Notice that, so far, we didn't signal any difference between a structure and a class, but there is one. In a structure, if you don't specify the private and public members, all members considered public. In a class, if you don't specify the private and public members, all members considered private. Based on this, to show the level of access of the members of your class (whether struct or class), precede each with the desired level: private: or public:.

Notice that you can create as many public: sections or as many private: sections as you want. When creating a class with different public and private sections, all of the declared variables under an access level keyword abide by the rules of that access level. The fact that you use different public sections does not give different kinds of public levels to the variables. A variable declared as public in one public section has the same public level of access as any other variable that is declared in another public section. There is no rule as to which section should come first. Simply remember that, for a class, if the top members are not given a level of access, then they are private.

When a member is declared private, you cannot access it outside of its class. Based on this rule, the following program will not compile:

using namespace System;

public value class CHouse
{
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CHouse townhouse;

	townhouse.YearBuilt = 1986;
	townhouse.Bathrooms = 1.5;
	townhouse.Stories = 3;
	townhouse.Value = 348255;
	townhouse.Bedrooms = 3;
	townhouse.TypeOfHome = L'T';

	return 0;
}

Remember that when an access level is not set for a class, all of its members are private by default. The above program would produce the following errors:

error C2248: 'CHouse::YearBuilt' : cannot access private member declared in class 'CHouse'
     	see declaration of 'CHouse::YearBuilt'
        see declaration of 'CHouse'
error C2248: 'CHouse::Bathrooms' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Bathrooms'
        see declaration of 'CHouse'
error C2248: 'CHouse::Stories' : cannot access private member declared in class 'CHouse'
        .see declaration of 'CHouse::Stories'
        see declaration of 'CHouse'
error C2248: 'CHouse::Value' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Value'
        see declaration of 'CHouse'
error C2248: 'CHouse::Bedrooms' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Bedrooms'
        see declaration of 'CHouse'
error C2248: 'CHouse::TypeOfHome' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::TypeOfHome'
        see declaration of 'CHouse'
error C2248: 'CHouse::TypeOfHome' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::TypeOfHome'
        see declaration of 'CHouse'
error C2248: 'CHouse::Bedrooms' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Bedrooms'
        see declaration of 'CHouse'
error C2248: 'CHouse::Bathrooms' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Bathrooms'
        see declaration of 'CHouse'
error C2248: 'CHouse::Stories' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Stories'
        see declaration of 'CHouse'
error C2248: 'CHouse::YearBuilt' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::YearBuilt'
        see declaration of 'CHouse'
error C2248: 'CHouse::Value' : cannot access private member declared in class 'CHouse'
        see declaration of 'CHouse::Value'
        see declaration of 'CHouse'

The following program will not compile either:

using namespace System;

public value struct CHouse
{
private:
	__wchar_t TypeOfHome;
	int Bedrooms;
public:
	double Bathrooms;
private:
	Byte Stories;
	int YearBuilt;
	double Value;
private:
};

int main()
{
	CHouse townhouse;

	townhouse.YearBuilt = 1986;
	townhouse.Bathrooms = 1.5;
	townhouse.Stories = 3;
	townhouse.Value = 348255;
	townhouse.Bedrooms = 3;
	townhouse.TypeOfHome = L'T';

	Console::Write("TypeOfHome:          ");
	Console::WriteLine(townhouse.TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(townhouse.Bedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(townhouse.Bathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(townhouse.Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(townhouse.YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(townhouse.Value);

	return 0;
}

This time, although this is a structure, the members that have been marked as private are no longer accessible outside of the class.

Practical LearningPractical Learning: Controlling the Access to a Class

  1. To make the CHouse a class, access the Property.h file and change it as follows:
    #pragma once
    
    public value class CHouse
    {
    public:
        long PropertyNumber;
        __wchar_t PropertyType;
        unsigned Stories;
        unsigned Bedrooms;
        float Bathrooms;
        unsigned YearBuilt;
        double MarketValue;
    };
  2. Execute the application to see the result
  3. Close the DOS window

Type-Defining a Class

Just as you can type-define the name of a built-in data type, you can do the same for any class. As reviewed for primitive types, when doing this, remember that you are not creating a new type: you are only providing a pseudo-name for an existing class. Here is an example:

public value class CHouse
{
public:
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	typedef CHouse Home;

	Home singleFamily;

	return 0;
}

You can also type-define a class outside of any function to make the name global.

Constant Objects

Just as you can create a constant of a built-in data type, you can also create a constant of a class. Always remember that the constant refers to a value that doesn't change and the constant value must be initialized with a known or already defined value. Here is an example:

using namespace System;

public value class CHouse
{
public:
	__wchar_t TypeOfHome;
	int Bedrooms;
	double Bathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	const CHouse singleFamily = { L'S', 5, 2.5, 3, 1962, 524885 };

	Console::Write("Type of Home:        ");
	Console::WriteLine(singleFamily.TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(singleFamily.Bedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(singleFamily.Bathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(singleFamily.Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(singleFamily.YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(singleFamily.Value);

	return 0;
}

Unions

 

Introduction

A union is another type of class of the C++ language. Like the other two, it is created from combining other identified variables. To create a union, use the union keyword following the same syntax applied for a structure, like this:

union UnionName {};

Like another class, the members of a union are listed in its body. For example, to create an object that represents a student, using a union, you could define it as follows:

union CHouseAge
{
    int YearBuilt;
    int Age;
};

Once the union is defined, you can declare it and use its members:

using namespace System;

union CHouseAge
{
    int YearBuilt;
    double Age;
};

int main()
{	
    CHouseAge home;

    home.YearBuilt = 1972;
	
    Console::Write("The house was built in = ");
    Console::WriteLine(home.YearBuilt);

    return 0;
}

This would produce:

The house was built in = 1972
Press any key to continue . . .

Using a Union

When creating a class of struct or class type, each variable, treated as its own entity, occupies its assigned amount of space in memory. This is different with unions. All of the members of a union share the same memory space. After declaring a union object, instead of allocating memory for each member variable, the compiler assigns an amount of memory equal to the largest variable. If you define a union that would represent a CHouseAge object as the above, the compiler would assign the same memory space to all members; and the compiler would find out which member needs the largest space. In our example, the Age member variable uses more memory than the YearBuilt. Therefore, the compiler will allocated the amount of memory required by a double, then all member variables would share that memory. Consequently, a union can store the value of only one of its members at a time: you cannot simultaneously access the values of all members, at the same time. If you initialize all of the members of a union at the same time, the result is unreliable; since all members are using the same memory space, that space cannot accommodate all member values at the same time.

Because only one member of a union can be considered for an instance of the object, use a union you are in an "either of one" scenario. For example, when processing our CHouseAge object, we want Either the year the house was built OR its age. We don't need both values. In fact this would create redundancy in the program. Notice that, if we know the year the house was built, we can deduct its age. On the other hand, if we know the age of the house, we can calculate the year it was built.


Previous Copyright © 2006-2025, FunctionX Monday 14 October 2024, 10:12 Next