< .Net Type, Variable & Operator 4 | Main | .Net Type, Variable & Operator 6 >


 

 

Data Types, Variables and Operators 5

 

 

 

 

 

 

The discussion and the codes used supposed to be based on the new C++ .NET. The following are the topics in this part.

  1. Derived Types

  2. C++ Classes

  3. C++ Structures

  4. C++ Unions

  5. Defining Class Types

  6. Overview of C++ Classes

  7. Class Names

  8. Class Members

  9. Member Functions

  10. Static Data Members

 

Derived Types

 

Derived types are new types that can be used in a program, and can include directly derived types and composed derivative types. The following sections will try to describe the composed derivative types: Classes, Structures and Unions. The discussion is biased to the traditional C++ instead of .Net. We will learn more about .Net implementation of these constructs in another module. The struct information is omitted because of the similarities to the class.

 

C++ Classes

 

Classes are a composite group of member objects, functions to manipulate these members, and (optionally) access-control specifications to member objects and functions. By grouping composite groups of objects and functions in classes, C++ enables programmers to create derivative types that define not only data but also the behavior of objects. Class members default to private access and private inheritance.

 

C++ Structures

 

C++ structures are the same as classes, except that all member data and functions default to public access, and inheritance defaults to public inheritance.

 

C++ Unions

 

Unions enable programmers to define types capable of containing different kinds of variables in the same memory space.

 

Defining Class Types

 

Class types are defined using class specifiers. Class types can be declared using elaborated type specifiers as shown in Type Specifiers. The class specifier consists of:

  1. The class, struct or union keyword.

  2. The class heading. The class heading includes the class name and the applicable template heading.

  3. Optionally, a colon and the base list which identifies the base classes that the class being defined inherits from.

  4. Braces ({}) containing the class member declarations.

 

Class names are introduced as identifiers immediately after the compiler processes them (before entry into the class body); they can be used to declare class members. This allows declaration of self-referential data structures, such as the following:

// defining class types

// compile with: /clr

class Tree

{

      public:

            void *Data;

            Tree *Left;

            Tree *Right;

};

Classes, which can contain data and functions, introduce user-defined types into a program. User-defined types in traditional programming languages are collections of data which, taken together, describe an object's attributes and state. Class types in C++ enable you to describe attributes and state, and to define behavior.

 

Overview of C++ Classes

 

Class types are defined using the class, struct, and union keywords. For simplicity, types defined with these keywords are called class declarations, except in discussions of language elements that behave differently depending on which keyword is used. Names of classes defined within another class ("nested") have class scope of the enclosing class. The name of a class may be either an identifier or a template identifier. The variables and functions of a class are called members. When defining a class, it is common practice to supply the following members (although all are optional):

  1. Class data members, which define the state and attributes of an object of the class type.

  2. One or more "constructor" functions, which initialize an object of the class type.

  3. A "destructor" function, which performs cleanup functions such as de-allocating dynamically allocated memory or closing files.

  4. One or more member functions that define the object's behavior.

 

Class Names

 

Class declarations introduce new types, called class names, into programs. These class declarations also act as definitions of the class for a given translation unit. There may be only one definition for a given class type per translation unit. Using these new class types, you can declare objects, and the compiler can perform type checking to verify that no operations incompatible with the types are performed on the objects. An example of such type checking is:

// Variables.cpp : main project file.

// class names

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

class Point

{

      public:

            unsigned x, y;

};

 

class Rect

{

      public:

            unsigned x1, y1, x2, y2;

};

 

// Prototype a function that takes two arguments, one of type

//  Point and the other of type pointer to Rect.

int PtInRect(Point, Rect &);

 

int main()

{

      Point pt;

      Rect  rect;

 

      rect = pt;   // C2679 Types are incompatible.

      pt = rect;   // C2679 Types are incompatible.

 

      // Error. Arguments to PtInRect are reversed.

      // Console::Write("Point is");

      // Console::Write("{0}", (PtInRect( rect, pt ) ? "" : "not"));

      // Console::WriteLine(" in rectangle");

}

As the preceding code illustrates, operations (such as assignment and argument passing) on class-type objects are subject to the same type checking as objects of built-in types. Because the compiler distinguishes between class types, functions can be overloaded on the basis of class-type arguments as well as built-in type arguments.

 

Class Members

 

Classes can have these kinds of members:

 

  1. Member functions.

  2. Data members.

  3. Classes, which include classes, structures, and unions.

  4. Enumerations.

  5. Bit fields.

  6. Friends.

  7. Type names.

 

 Friends are included in the preceding list because they are contained in the class declaration. However, they are not true class members, because they are not in the scope of the class. The member list of a class may be divided into private, protected and public sections using keywords known as access specifiers. A colon : must follow the access specifier. These sections need not be contiguous, that is, any of these keywords may appear several times in the member list. The keyword designates the access of all members up until the next access specifier or the closing brace. Member declarations in the member list are separated by semicolons ;. The purpose of the member list is to:

 

  1. Declare the complete set of members for a given class.

  2. Specify the access (public, private, or protected) associated with various class members.

 

In the declaration of a member list, you can declare members only once; re-declaration of members produces an error message. Because a member list is a complete set of the members, you cannot add members to a given class with subsequent class declarations. Member declarators cannot contain initializers. Supplying an initializer produces an error message as illustrated in the following code:

// class members

// C2864 expected

class CantInit

{

      public:

            // Error: attempt to initialize class member.

            long l = 7;

            // Error: must be defined and initialized

            // outside of class declaration.

            static int i = 9;

};

 

int main()

{

      return 0;

}

Because a separate instance of nonstatic member data is created for each object of a given class type, the correct way to initialize member data is to use the class's constructor. There is only one shared copy of static data members for all objects of a given class type. Static data members must be defined and can be initialized at file scope. The following example shows how to perform these initializations:

// Variables.cpp : main project file.

// class members

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

class CanInit

{

      public:

            // Initializes l when new objects of type CanInit are created.

            CanInit() { l = 7; }

            long       l;

            static int i;

            static int j;

};

 

// i is defined at file scope and initialized to 15.

// The initializer is evaluated in the scope of CanInit.

int CanInit::i = 15;

 

// The right side of the initializer is in the scope

// of the object being initialized

int CanInit::j = i; 

 

int main()

{

      return 0;

}

 

Output: none

The class name, CanInit, must precede i to specify that the i being defined is a member of class CanInit. Microsoft C++ allows static, const integral, and const enum data members to be initialized in the class definition and this is Microsoft implementation.

 

Member Functions

 

Classes can contain data and functions. These functions are referred to as "member functions." Any nonstatic function declared inside a class declaration is considered a member function and is called using the member-selection operators (. and –>). When calling member functions from other member functions of the same class, the object and member-selection operator can be omitted. For example:

// Variables.cpp : main project file.

// member functions

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

class Point

{

      public:

            short x(){ return _x; }

            short y() { return _y; }

            void  Show()

            {

                  Console::Write(x());

                  Console::Write(", ");

                  Console::WriteLine(y());

            }

      private:

            short _x, _y;

};

 

int main()

{

      Point pt;

      pt.Show();

}

 

Output:

Class member function program output sample

 

Note that in the member function, Show, calls to the other member functions, x and y, are made without member-selection operators. These calls implicitly mean this->x() and this->y(). However, in main, the member function, Show, must be selected using the object pt and the member-selection operator (.). Static functions declared inside a class can be called using the member-selection operators or by specifying the fully qualified function name (including the class name). A function declared using the friend keyword is not considered a member of the class in which it is declared a friend (although it can be a member of another class). A friend declaration controls the access a nonmember function has to class data. The following class declaration shows how member functions are declared and called:

// Variables.cpp : main project file.

// member functions

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

class Point

{

      public:

            unsigned GetX()

            {

                  return ptX;

            }

            unsigned GetY()

            {

                  return ptY;

            }

            void SetX( unsigned x )

            {

                  ptX = x;

                  Console::WriteLine("ptX = {0}", ptX);

            }

            void SetY( unsigned y )

            {

                  ptY = y;

                  Console::WriteLine("ptY = {0}", ptY);

            }

      private:

            unsigned ptX, ptY;

};

 

int main()

{

      // Declare a new object of type Point.

      Point ptOrigin;

      // Member function calls use the . member-selection operator.

      ptOrigin.SetX( 0 );

      ptOrigin.SetY( 0 );

      // Declare a pointer to an object of type Point.

      Point *pptCurrent = new Point;

      // Member function calls use the -> member-selection operator.

      pptCurrent->SetX( ptOrigin.GetX() + 10 );

      pptCurrent->SetY( ptOrigin.GetY() + 10 );

 

      return 0;

}

 

Output:

 

Another class member function program output sample

 

In the preceding code, the member functions of the object ptOrigin are called using the member-selection operator (.). However, the member functions of the object pointed to by pptCurrent are called using the –> member-selection operator.

 

Static Data Members

 

Classes can contain static member data and member functions. When a data member is declared as static, only one copy of the data is maintained for all objects of the class. Static data members are not part of objects of a given class type; they are separate objects. As a result, the declaration of a static data member is not considered a definition. The data member is declared in class scope, but definition is performed at file scope. These static members have external linkage. The following example illustrates this:

// Variables.cpp : main project file.

// static data members

// compile with: /clr

#include "stdafx.h"

 

using namespace System;

 

class BufferedOutput

{

      public:

            // Return number of bytes written by any object of this class.

            short BytesWritten()

            {

                  return bytecount;

            }

 

            // Reset the counter.

            static void ResetCount()

            {

                  bytecount = 0;

            }

 

            // Static member declaration.

            static long bytecount;

};

 

// Define bytecount in file scope.

long BufferedOutput::bytecount;

 

int main()

{

      return 0;

}

// No output

In the preceding code, the member bytecount is declared in class BufferedOutput, but it must be defined outside the class declaration. Static data members can be referred to without referring to an object of class type. The number of bytes written using BufferedOutput objects can be obtained as follows:

long nBytes = BufferedOutput::bytecount;

For the static member to exist, it is not necessary that any objects of the class type exist. Static members can also be accessed using the member-selection (. and –>) operators. For example:

BufferedOutput Console;

long nBytes = Console::bytecount;

In the preceding case, the reference to the object (Console) is not evaluated; the value returned is that of the static object bytecount. Static data members are subject to class-member access rules, so private access to static data members is allowed only for class-member functions and friends. The exception is that static data members must be defined in file scope regardless of their access restrictions. If the data member is to be explicitly initialized, an initializer must be provided with the definition. The type of a static member is not qualified by its class name. Therefore, the type of BufferedOutput::bytecount is long.

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7 | Part 8 | Part 9 | Part 10

 


 

< .Net Type, Variable & Operator 4 | Main | .Net Type, Variable & Operator 6 >