Contents Page

Miscellaneous

Aug 22, 2001

C++ Class Design Helper

Contents

q       Access Specifiers

q       Arrays of Class Objects

q       Class Declaration

q       Class Naming

q       Constructor Functions

q       Data Members

q       Derived Classes

q       Destructors

q       Friend Functions

q       Glossary

q       Initializers

q       Inline Functions

q       Keywords

q       Member Functions

q       Multiple Inheritance

q       Operators

q       Overloading

q       Parameter Initialization Lists

q       Pointers

q       Private Classes

q       Qualifiers

q       References to Data Members

q       Storage Classes

q       Text References

q       Templates

q       TypeCasting and Type Conversions

q       Virtual Base Classes

 

Class Declaration        

 

#include

class Id1   {     //Class naming conventions

private:

            //Declarations for private members of this class - member data, and member functions

            //Optional inline functions

public:

            //Declarations for the public member this class, including  constructor functions .

            Id1 (     );   //Sample constructor for the Id1 class

            //Optional copy constructor       

//Optional inline functions

            //Optional destructor

};  //End of the class declaration for class Id1

//Optional inline functions using the inline keyword

Class Objects - i.e., instances of classes:

const Objects:

An object can be declared const. That means that its data members cannot be altered. Any member function provided to access a const object must be a const member function.

Back to top

 

Access Specifiers

The public and private access specifiers specify the visibility of the members that follow.  In a class declaration, the access is private by default until an explicit access specifier is encountered.

 

public:       

Public members can be accessed by member functions and by functions that declare an instance of the class.

A class member that is public static is accessible to the entire program and is not associated with a specific instance of the class. A public static member function is not quite global. It exists only within the scope of the class in which it is defined, and it can be called from anywhere within that scope using the :: scope resolution operator.

 

private:     

Private members can only be accessed by member functions of the class.

 

protected: 

Protected members are not available to users of the class. If a program instantiates an object, the program cannot access the protected members of that object. In this respect, protected members are the same as private members. If a base class has private members, those members are not accessible to the member functions of any derived class. Protected members are public to member functions of classes derived from the base class and private to the rest of the program. When designing a class, consider whether the class may someday be derived from - even if you initially have no such intentions. Specify the protected keyword for members that could be accessible to derived classes.

Back to top

 

Arrays of Class Objects

Declare an array of classes as follows:

Class_name  instance_name[ #OfElements];  //The default constructor function will be called once for each element of the array

 

In order to support arrays of class objects, the class must have a default constructor – either one with no arguments, or one with default arguments. [The notation for declaring an array of objects does not provide for an initializer list that conforms to the format of constructor function arguments.]

 

Back to top

 

Class Naming Conventions

Capitalization:

Class names are typically begun with capital letters. This is to help distinguish between classes and member data variables and member functions, which are typically begun with lower case letters.

 

Back to top

 

Constructor Functions

The constructor function has the job if initializing the data members of the class when an object is instantiated. The constructor has the same name as the class and is automatically executed when an object of  the class is instantiated. The constructor function has no return value.

The constructor function is always public (except in the case of private classes, which have private constructors.). The compiler will error if you try to instantiate an object if the constructor is not public.  It is illogical to have a constructor that is not public – there would be no way to instantiate objects and no way to derive classes from it.  A constructor cannot be virtual. A constructor cannot have a return type – not even void.

 

Don’t try to perform too many tasks with a constructor. A constructor should only be concerned with initializing values for an object. It shouldn’t be performing the main task of the object.

If the constructor function requires parameters, the instantiation includes initializer arguments corresponding to the parameter list in the constructor's prototype. The simplest constructor is none at all. In that case the compiler provides a public default constructor that usually does nothing. The next level of constructor complexity is a constructor that you provide with an empty parameter list, which does nothing. In that case the instantiation of the object leaves off the parenthesis. The next level of complexity is a  constructor that provides default values for all of its parameters. For example:

Box(int ht=0, int wd = 0, int dp = 0);

Overloaded Constructors:

A class can have more than one constructor function, which means that the constructor is "overloaded". Overloaded constructors may provide different parameter lists with either a different number of arguments or with arguments of different type including the empty parameter list.

Conversion Constructors:

A conversion constructor accepts one and only one argument, which must be of a different type than the class of the constructor.

Class_name::Class_name ( type arg1)

{

            //Code that does the actual conversion of the arg1 into an object of type Class_name

}

 

Context in which a Conversion Constructor would be used:

Date dt(6, 29, 90);                  //Date object, dt

DayOfYear dy;                     //DayOfYear object dy

dy = dt;                                  //In all three of these, the conversion constructor would be used by the compiler to make the conversion

dy = (DayOfYear) dt;

dy = DayOfYear(dt);

 

Copy Constructors:

The purpose of a copy constructor is to copy an existing object of a class to a newly instantiated object of the same class. The compiler provides a default copy constructor if you do not. The default copy constructor simply makes a member by member copy of the source object's data members. The danger of such a default copy constructor is that the data member may be a dynamically created (via "new")  array of char and it is the pointer to the array that gets copied by the default copy constructor. That results in two pointers pointing to the same memory location in the heap. The first of the objects that goes out of scope causes the array's memory in the heap to be de-allocated (returned to the free store), but when the next object goes out of scope and the destructor tries to de-allocate that same memory, the results are unpredictable. Such misadventures can be avoided by implementing a constructor that allocates the appropriate amount of memory for the new object's data member, using "new", and then copies the original object's data member value(s) to the new variable. In that way, when the destructor is called, the allocated memory for each object is separate and unique.

 

Derived Class Constructors:

Unless the base class has a default constructor, you must provide a base class parameter initialization list.

The compiler causes execution of the base class’s constructor before it executes the derived class’s constructor. Therefore the constructor function of the derived class must tell the compiler what values to use as arguments to the constructor function for the base class.  The derived class’s constructor specifies the arguments to the base class’s constructor function using a parameter initialization list for the base class, as shown here:

SpecialDayOfYearDate(int yr, int da)  :  Special Date(0, 0, 0) 

/*  Where SpecialDayOfYearDate is the derived class

  and SpecialDate is the base class */

{

}

 

The constructor function declaration in a class derived from multiple bases specifies the arguments for the constructors of all the base classes, as shown here:

 

CompanyCar :: CompanyCar ( int vehno, int assetno) : Vehicle(vehicleno) ,  Asset (assetno)

{

//…

}

 

The order of execution of constructors in the above example is Vehicle,  then Asset and CompanyCar is last.

See also Multiple Inheritance.

 

Back to top

 

Data Members of a Class

Member Data: 

Member data can be any valid C++ data type, including an instance of another class or a pointer or a reference. Member data can be declared static, const or both.

 

static Data Members:

Declaring a data member as static means that it is a class-wide variable rather than a per instance variable. That is, all objects of the class access the same variable, whereas each instance of a class receives its own instance of each non-static variable.  A static data member must be defined from outside the class declaration using the scope resolution operator and the class name. [See the exception to this in the case of  static const data members.]  For example,

datatype class_name::static_variable_name  = …..;    // Do not use the keyword static here

 

The static variable would have already been declared inside the class, as follows:

class_name   {

           

static datatype static_variable_name;  //Use the keyword static here

}

Only one copy of a static data member exists, regardless of how many objects of the class are instantiated. Do not confuse static data members with static storage or static linkage.  They are independent of one another.

 

const Data Members:

Data members of a class can be declared const by using the keyword const before the datatype. Constant data members must be initialized. In order to initialize a const data member in the constructor, you use a parameter initialization list.

 

static const Data Members:

Data members that are static can be further qualified as const and can be initialized directly in the class declaration. In that case, the data member does not need to be defined outside of the class definition.

explicit Constructors:

Class Time {

            //…

            explicit Time(int  secs);

};

 

Without the keyword, explicit, the compiler would make an implicit, silent conversion when an integral value is found where a Time object was expected.

Time time(21);          //OK – explicit construction

time = 12;                   //Error, implicit construction – in other words, the compiler would error out saying that it cannot do the implicit conversion.

 

protected Data Members:

The protected access specifier is a measure that may be used to support subsequent derivations from a class.

 

Back to top

 

Derived Classes

 

Declaration of Derived Classes:

classDerived : public BaseClass   {

            //…A class derived from class BaseClass

};

 

The constructor(s) and destructor(s) of the base class must be public (or protected). [If the constructor is protected, the class will be an abstract base class.]

Characteristics in a class that will enhance its role as a base class:

          Use of the virtual qualifier with the destructor  and other member functions.

          Use of the protected access qualifier with data members.

 

public or private reference to the Base Class:

In the declaration of the derived class, the use of the public access specifier means that the protected members of the base class are protected members of the derived class and the public members of the base class are public members of the derived class.  The private access specifier means that the protected and public members of the base class are private members of the derived class.

 

 

Back to top

 

Destructors

When a class object goes out of scope (including use of the delete keyword), the destructor function is called.

The destructor function has the name of the class prefixed by the "~", and there is only one destructor function for a class.

A destructor function has no parameters and does not return a value (no return type).

An important rationale' for a destructor is to return memory to the heap (free store). Data members that were created dynamically by the class object via the "new" keyword should be deleted (returned to the heap) using the delete keyword.

If your class declaration does not explicitly provide a destructor, the compiler provides a "do nothing", default  destructor function.

 

virtual Destructors:

It is important that a base class provide a virtual destructor. In that way, the derived classes can override the virtual destructor with an appropriate destructor, which will execute before the base class destructor – otherwise only the base class destructor executes, which is not going to be able to properly delete derived objects and return their memory to the heap. The order of execution for destructors in the case of multiple inheritance is the reverse of the order of execution of the constructors.

Back to top

Friend Functions

The prototype of the friend function is placed inside of the class declaration using the keyword friend. [A class determines who its friend functions are – the functions themselves don’t.]

class Point  {

public:

friend int compare(point &a, point &b):   //The friend function is NOT in the scope of the Point class.

};

Implementation of “compare” outside of class Point:

int compare(point &a, point &b)

{

   //This friend function cannot access member data of Point directly – only through Point objects.

return ….;

}

There are also two other ways of making friends of member functions in other classes. You can call out the member function as a friend, as above, but also use the full name of the member function with its class and scope resolution operator. You can also make the another class a friend class by declaring it in your class, as follows:

class Point  {

public:

friend MumbleFratz;   //Now all member functions of MumbleFratz are friend functions of Point

};

 

Back to top

 

Glossary

 

Abstract Class – See Virtual Member Functions and Derived Classes.

Arguments – (also known as “dummy arguments” - the data passed as a list of one or more elements to a function by its calling program. The argument list must conform to the parameter list in the function's prototype.  Contrast with "Parameters"!

Assignment – An assignment statement assigns the value returned by an expression  to a variable.

Attributes – each data item has five attributes associated with it, as given in this table:

Data type

Determines how the data is encoded and operated on

Storage class

Determines where the data is stored

Duration

Determines how long the data exists

Linkage

Determines the accessibility of data in multiple-file programs

Scope

Determines the visibility of data

 

Declaration - The program statement that associates an identifier with what it identifies. A declaration can declare a variable, specify the format of a structure, declare an external variable, or declare a function or subroutine's return value and parameter list. A declaration may or may not reserve memory. To declare a user defined data type is to provide the plan, or specification, for the data type.  Declarations are an abstraction. To declare a function is to provide its prototype, i.e., its identifier, return type and parameter list.

 

Default – Depending upon the context, “default” can mean “the function having no parameters”, or it can mean “the item or value that is provided by default” – i.e., in lieu of a provided item or value.

 

Default Constructor – a  “default” constructor is a constructor with no arguments.

Definition - The program statement that defines the existence of a variable or function. A definition reserves memory for the item. The definition sometimes doubles as the item's declaration.  To define a variable or an instance of a class is to assign a value and store it in memory. Using a variable that has been declared but not yet defined causes a compiler error.  To define a function is to provide or implement the code for the function in accordance with its prototype.

Dummy arguments – a term used to refer to the arguments passed to a function by the calling routine. .

Duration – the life of the variable in regards to how long it has real physical memory attached to it. The three categories of “duration” are as follows:

Static

Data segment

During the entire program

Automatic

Stack or register

During a function call

Dynamic

Heap

User controlled

 

Expression – a combination of constants, variables, function calls, and operators, which, when evaluated, returns a value.

Inline and the keyword inline  A member function that is implemented directly in the class declaration can  be considered to be “ inline”, just as if it had the inline keyword. If it is coded outside of the class declaration, then it can still be made “inline” by use of the inline keyword. A member function that is coded outside of the class declaration  and does not use the keyword inline is not “inline”. An “inline”  function is a function that is considered by the compiler for direct incorporation of its body into the code wherein it is called. There is no guarantee that the compiler will “inline” the function, but it will generally do so when possible ( see also Horton, page 287).

Linkage – an attribute of both data and functions that is related to their visibility or accessibility in programs that are made up of multiple translation units.  The two types of linkage are static (also known as internal) linkage and external linkage. The linkage for an identifier is specified using the static and extern keywords. Identifiers with static linkage are accessible in the modules (translation units) in which they are declared. Statically linked variables and functions do not appear in the object files created by the compiler, thus the linker cannot see them. Variables and function declared with external linkage are in the object files, and are visible to the linker. Thus, many modules can share an externally linked identifier.

Parameters - The list of one or more data elements seen by the called function in its "parameter list".  Parameters are declared in the function's prototype.  Contrast with "arguments" or “dummy arguments”.

Scope – the visibility or accessibility attribute of data and functions - there are five scopes in C++, as shown in the following table:

Block

The area between the curly braces in a function

Function

Applies only to statement labels inside functions

Function prototype

The dummy arguments inside a function prototype

File

The areas outside function and class declarations

Class

Inside the curly braces of a class declaration

 

Translation Unit – an independently compiled program module consisting of a C++ source code file and any other source code files the program includes.

 

Type-safe Linkage – the C++ compilers and link editors perform type-safe linkage by checking argument types when linking a function call to the code for the function. See also name mangling.

Use - to use a variable is to include it on the right side of an assignment statement or to include it anywhere in a conditional clause. "Use" implies "read" - not write.

Back to top

 

Initializers

There are two formats for initializing variables as part of the declaration, as follows:

int  amount  = 3;   char ch = ‘A’;     float val = 1.23;  //etc.

int amount(3);       char ch(‘A’);       float val(1.23);    // unique to C++

 

If the declaration is for a local static variable, then it will be initialized the first time but never again.

Initializer Lists are used for initializing structures and arrays. For example:

int numbers[3] = {1, 2, 3};

There are rules for determining when you can use an initializer list to initialize an object, as follows:

·        The object can’t have private members

·        The object can’t have constructors

·        The object can’t have virtual functions

·        The object can’t be from a derived class

·        If you’re trying to create and initialize an array of objects that have at least one of the four properties listed above, then you can’t use an initializer list unless the objects have a constructor. In that case, you can initialized each object in the array by calling a constructor in the initializer list. See Flamig, page 189, and also see Constructor Functions and Constructor Functions - default values.

Back to top

 

 

Inline Functions

 

An “inline” function is a function that is defined (implemented) within the class declaration,  or by means of the inline keyword.

Two notations exist for defining (implementing) inline functions for a class. In the first, you code the body of the function directly into the class declaration - i.e., within the class declaration curly brackets. The second notation uses the inline keyword outside the class. When using the second method, the implementing code should be included in a header file, along with the class declaration. In this way, the code will be visible to all code that uses the class.

 

Back to top

 

Standard C++ Keywords

 

asm

const_cast

explicit

int

register

switch

union

auto

continue

extern

long

reinterpret_cast

template

unsigned

bool

default

false

mutable

return

this

using

break

delete

float

namespace

short

throw

virtual

case

do

for

new

signed

true

void

catch

double

friend

operator

sizeof

try

volatile

char

dynamic_cast

goto

private

static

typedef

wchar_t

class

else

if

protected

static_cast

typeid

while

const

enum

inline

public

struct

typename

 

 

 

Back to top

 

Member Functions of a Class

Member functions are the functions you declare within the class definition. You must provide code for these functions (implementation). Member functions are named with the class name, followed by the :: operator, followed by the function name.

Calling Member Functions:

A program calls a member function by using a period operator, as shown here:

int vol = thisbox.volume(); //Where "thisbox" is the name of a specific instance of the class and volume() is the member method of that same class.

static Member Functions:

You would declare a member function static when it is intended to be used only to access static data members rather than the data members of any particular instances of that class. Static member functions can be defined inline or outside the class as with any member function. A static member function cannot access any non-static data members nor can it call any non-static member functions. Since static member functions have no access to non-static member data, they have no need for the this pointer and cannot use it.

const Member Functions:

You would declare a member function const when objects of the class are to be declared const at instantiation. [An object might be declared const because you do not want its data members to be modified.]  A const member function cannot call a non-const member function of the same class, since this would potentially modify the object. A member function is declared constant by appending the keyword const to the function header (Horton, page 308). For example:

class Date {

            void  display( )  const;

//…

};

void  Date::display( )  const {   }

 

 

Member Conversion Functions:

A Member Conversion Function converts an object of the class in which it is installed to an object of another type. The declaration of a member conversion function is as follows:

operator target_conversion_type(); //keyword “operator” followed by the “type” returned by the function.

The member conversion function is defined as follows:

Classname::operator  target_conversion_type()

{

            //This function starts with an object of type “Classname” and returns an object of class “target_conversion_type”

}

The keyword const may appear directly after the parens in both declaration and definition in order to guarantee that the original object is not modified by the function.

Context in which Member Conversion Function would be used:

Class Date {

            operator long();

};

 

Date today(2.12,98);

long sum = 123 + today; //Compiler makes use of the member conversion function to convert “today” to long.

 

Also:

DayOfYear  rtndate()

{

            Date dt (10,11,88);

            return dt;   //Compiler would use the conversion function to convert to a DayOfYear object.

}

 

Two Way Conversions:

A class may contain both a “conversion constructor” and a “member conversion function” which implement 2-way conversions between that class and another class. However, note that there cannot be a “conversion constructor” in ClassA and also a “member conversion function” in ClassB, both of which produce an object of type ClassA, because the compiler would not know which to call.

 

virtual Member Functions:

The virtual qualifier on a member function is used to support polymorphism by subsequent derivation from a class. Member functions may use the virtual qualifier to indicate that the function is expected to be overridden in the derived class by a function with the same name and parameter list.

[Question: If the base class is not abstract, and if the derived class does not override the virtual member function, will there be a compile error? The answer is no. See example programs, 20-1 and 20-2 in Stevens. In those examples, the base class is not abstract, and its virtual function, foo( ), is not overridden in the derived classes.]

 If a virtual member function prototype ends with “ = 0; “, that signifies a pure virtual function and also means that the base class is an abstract base class, which means the designer intends the class to be used only as a base class. Furthermore, the virtual member function must be overridden in  any derived class that uses it. A consequence of a class being abstract is that objects cannot be instantiated from that class.

See also, constructor functions.

Back to top

 

Multiple Inheritance

You specify more than one base class when you define a derived class with multiple inheritance. The following  code shows how you define the CompanyCar class given that the Vehicle and Asset class definitions are in scope:

class CompanyCar  :  public Vehicle, public Asset   {

//…

};

 

Overriding Members with Multiple Inheritance:

Member functions in the derived class that override the virtual functions of the base classes may call the base class function using the scope resolution operator as follows:

void DerivedClass : : functionX ( )

{

BaseClass1 :: functionX();

BaseClass2 :: functionX();  //If the function does not exist, the compiler searches up the hierarchy until a matching function is found.

}

 

Ambiguity Due to Missing Function:

When the derived class has not overridden a virtual function of the base classes, then the client program must use the scope resolution operator and call a base class function as follows:

LeaseCar myChevy;

MyChevy.Vehicle::Display();

Or ,

MyChevy.Expense::Display();

 

Ambiguous Data Members:

When two or more of the base classes have identically named data members and the derived class does not have such a data member, then the member functions of the derived class must use the scope resolution operator to resolve which data member to use, as follows:

LeaseCar myChevy;

….  Vehicle :: ctlno ….. ;

Or ,

….. Expense :: cltno …. ;

 

The preferred method of resolving ambiguities is to design the base classes with protected data members and use dedicated member functions in the derived class to access the specific base class data members.

Back to top

 

Operators

Arithmetic Operators

+         

Unary plus

Does nothing

-          

Unary minus

int y = -x;

*

multiplication

Prod = x * y;

/

Division

Byteoffset = bitno / 8;     //offset to the byte

%

Modulus

Bitoffset = bitno % 8;    //bit offset in the byte

+

Addition

x = y + z;

-

Subtraction

z = x – y;

--counter;

Decrement (prefix)

Changes the variable before it contributes to the expr.

counter--;

Decrement (postfix)

Changes the variable after it contributes to the expr.

--counter;

Increment (prefix)

Changes the variable before it contributes to the expr.

counter++;

Increment (postfix)

Changes the variable after it contributes to the expr.

Relational Operators

>

Greater than

 

<

Less than

 

>=

Greater than or equal to

 

<=

Less than or equal to

 

==

Equal to

See note below

!=

Not equal to

 

Operators for Members, Pointers and Scope Resolution

::

Scope resolution operator

 

.

Period operator

Class Member Operator

->

Indirect Member Select Operator

Pointer to Member Operator

Logical Operators

&&

Logical AND

 

||

Logical OR

 

!

Unary NOT

 

Bitwise Logical Operators

&

Bitwise AND

 

|

Bitwise OR

 

^

Bitwise eXclusive OR

 

~

One’s complement

 

Bitwise Shift Operators

<<

Left shift

 

>>

Right shift

 

Compound Assignment Operators

+=

Addition assignment

 

-=

Subtraction assignment

 

*=

Multiplication assignment

 

/=

Division assignment

 

%=

Modulus assignment

 

<<=

Shift left assignment

 

>=

Shift right assignment

 

&=

Bitwise AND assignment

 

|=

Bitwise OR assignment

 

^=

Bitwise eXclusive OR assignment

 

Miscellaneous Operators

,

Comma operator

Val = (amt++, -tot, cnt+3);  //Val=rightmost expression

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Note on assignment (=) vs. equality (==)

The following is a valid statement but may not be what the programmer intended:

If ( amount  = 123)    //…..

The variable amount will be assigned the value 123. Since 123 converts to boolean true, the if condition is satisfied. The programmer probably did not mean to assign a value to amount. If not, he programmer should have used the (==) equality operator.

 

Operator Precedence and Order of Evaluation

Op

Name

Pr

As

Ar

Ov

Example

::

Global Scope Resolution

17

R

1

N

::x

::

Class Scope Resolution

17

L

2

N

X::x

.

Direct Member selection

16

L

2

N

s.len

->

Indirect Member selection

16

L

2

Y

p->len

[ ]

Subscript

16

L

2

Y

a[i]

( )

Function Call

16

L

N/A

Y

rand()

( )

Type construction

16

L

N/A

Y

int(ch)

++

Post-increment

16

R

1

Y

n++

- -

Post-decrement

16

R

1

Y

n- -

Sizeof

Size of object or type

15

R

1

N

sizeof(a)

++

Pre-increment

15

R

1

Y

++n

- -

Pre-decrement

15

R

1

Y

- -n

~

Bitwise complement

15

R

1

Y

~s

!

Logical NOT

15

R

1

Y

!p

+

l plus

15

R

1

Y

+n

-

l minus

15

R

1

Y

-n

*

Dereference

15

R

1

Y

*p

&

Address

15

R

1

Y

&x

New

Allocation

15

R

1

Y

new p

Delete

Deallocation

15

R

1

Y

delete p

( )

Type conversion

15

R

2

Y

int (ch)

. *

Direct member selection

14

L

2

N

x.*q

->*

Indirect member selection

14

L

2

Y

p->q

*

Multiplication

13

L

2

Y

m*n

/

Division

13

L

2

Y

m/n

%

Remainder

13

L

2

Y

m% n

+

Addition

12

L

2

Y

M + n

-

Subtraction

12

L

2

Y

m – n

<<

Bit shift left

11

L

2

Y

cout << n

>>

Bit shift right

11

L

2

Y

cin >> n

<

Less than

10

L

2

Y

x < y

<=

Less than or equal to

10

L

2

Y

x <= y

>

Greater than

10

L

2

Y

x > y

>=

Greater than or equal to

10

L

2

Y

x >= y

==

Equal to

9

L

2

Y

x == y

!=

Not equal to

9

L

2

Y

x != y

&

Bitwise AND

8

L

2

Y

s&t

^

Bitwise XOR

7

L

2

Y

s^t

|

Bitwise OR

6

L

2

Y

s|t

&&

Logical AND

5

L

2

Y

u && v

||

Logical OR

4

L

2

Y

u || v

?:

Conditional expression

3

L

2

N

u ? x:y

=

Assignment

2

R

2

Y

n = 22

+=

Addition Assignment

2

R

2

Y

n += 8

-=

Subtraction assignement

2

R

2

Y

n -= 4

*=

Multiplication assignment

2

R

2

Y

n *= -1

/=

Division assignment

2

R

2

Y

n /= 10

%=

Remainder assignment

2

R

2

Y

n %= 10

&=

Bitwise AND assignment

2

R

2

Y

s &= mask

^=

Bitwise XOR assignment

2

R

2

Y

s ^= mask

|=

Bitwise OR assignment

2

R

2

Y

s |= mask

<<=

Bit shift left assignment

2

R

2

Y

s <<= 1

>>=

Bit shift right assignment

2

R

2

Y

s >>= 1

,

comma

0

L

2

Y

++m, - -n

Other authors present similar but different tables of precedence.  See Liberty, inside back cover.

Back to top

 

Overloading

Overloading Class new Operator:

void*  operator new (size_t)

{

            //Whatever code is needed to manage memory allocation

}

 

The argument to new is a type defined by the system that specifies memory sizes. I have not seen this explained anywhere, but it is logical that the compiler would have to provide the size of the memory required by the object being created and that the allocation would be dependent upon the class.  Whether the overloaded operator makes use of that parameter is irrelevant – it must be shown as above.

 

Overloading Class delete Operator:

void  operator delete(void* p)

{

            //Whatever code is needed to return the allocated memory to the free store

}

 

You must provide an overloaded delete operator, even if it does nothing – otherwise, the compiler calls the  default delete operator function when you use the delete operator, which assumes the function’s argument points to a buffer allocated from the heap. The results would be undefined and unpredictable .

 

Overloading Class new [ ] Operator:

The overloaded Class new and delete operators cannot be used when instantiating and deleting arrays of the Class objects. Declarations for overloading the new [ ]  and delete [ ] should be as shown in the following examples:

 

void*  operator new [ ] (size_t size)

{

            //Whatever code is needed to manage memory allocation, including maintaining a list of the allocated memory to be returned.

}

 

For example, the argument size might be used in keeping track of what amounts of memory have been allocated as well as a record of the pointer to that memory.

Overloading Class delete [ ] Operator:

void  operator delete [ ] (void* p)

{

            //Whatever code is needed to return the allocated memory to the free store, based on information maintained by the  overloaded new [ ] operator

}

 

Overloaded Assignment Operator:

Unless you overload the assignment operator, the compiler does a simple member by member assignment, which could lead to serious complications if the class allocates resources in the constructor.

Class MumbleFratz {

            MumbleFratz& operator=(const MumbleFratz&);  //Parameter in the parens refers to the object being assigned from – that is, the object that would be on the right side of the assignment.

};

 

Consider the following  code:

Date birthday(3,13,30);

Date newday;

newday = birthday;

 

The overloaded assignment operator function sees two parameters –  the first is implied and is the object for which the function is being called. In this case the function is being called for the object on the left side of the assignment: the newday object.  The second parameter is being supplied as an argument and is the object on the right side of the assignment, in this case the birthday object.  The assignment operator function will return a reference to the object that received the assignment (return *this;), making possible the following statement:

oldday = newday = birthday;

Class Member Operator ( . ) Functions:

Binary Arithmetic Operators can be overloaded, which will permit an expression like this:

olddate = olddate + 21;

They can also be used explicitly, as follows:

olddate.operator + (21);

Relational operators, auto-increment and decrement operators, and unary – operator can all be overloaded. The subscript operator, [ ], can be overloaded to provide subscripted access to a string value, as follows:

class String  {

            //…

            char& operator [ ] (int n);

            const char& operator [ ] (int n) const;

};

Because the operator [ ]  function returns a non-const reference to the character being subscripted, the program can use the expression on the left side of an assignment, like this:

 

String string1(“The Ides of March”);

String1[4] = ‘x’;  //which changes the string to “The xdes of March”

 

Pointer-to-Memory Operator (->):

The pointer-to-memory operator can be overloaded to become a smart pointer – that is, to ensure that a pointer to a class object always has a value. It must be implemented as a non-static member function.

 

Overloading the << and >> Operators:

Instead of writing functions that use std::cout and std::cin for output and input from the console, it makes more sense to modularize the display functions as follows:

void Classname::Display(std::ostream& os) const

{

            //….

            os <<  “text string” << variable << … ;

}

 

And then it might be used as follows:

object_name.Display(std::cout);  or object_name.Display(std::cerr);,   etc., depending on which device it should go to.

 

 

Back to top

 

Constructor Parameter Initialization Lists

The colon operator ( : ) is used to specify a parameter initialization list. 

 

Classname(param list) :  const_datamember1(param1), const_datamember2(param2), … {  }  //for an inline constructor

Classname::classname(param1, param1, param2,… ) : const_datamember1(param1), const_datamember2(param2), …

{

}           //for a constructor not inline.

 

To initialize references:

class DateTime  {

const Date& dt;         //reference to Date

const Time& tm;       //reference to Time

public:

DateTime (const Date& d, const Time& t) : dt(d), tm(t) {  }

};

 

Or, if the constructor is not inline:

 

DateTime :: DateTime (const Date& d, const Time& t) : dt(d), tm(t)

{

}

When the above constructor is invoked, the arguments, reference to a date and reference to a time are used to initialize the const member variables. From that point on, the object of class DateTime will be immutable (cannot be changed).

One way to initialize const data members:

class Date {

            const int months;

public:

            Date() : months(12) { } //Here the variable months is initialized to 12

};

To initialize the member objects of classes not having default constructors:

class Date {

            int da, mo, yr;

public:

            Date (int d, int m, int y) { da = d;  mo = m; yr = y; }

};

 

class DateTime  {

            Date dt;  //A Date object called “dt” – how is it to be initialized without an assignment operator ?

public:

            DateTime( int d, int m, int y)  :  dt(d, m, y) { }

};

 

Note that the above method permits the Date object, dt,  to be  initialized without using an assignment operator.

The parameter initialization list can be used to initialize all class object data members. Consider the following code:

 

class Employee {

            int empno;

            Date datehired; //Note that a Date object is instantiated assuming a default (no parameters) constructor.

public:

            Employee(int en, Date& dh);

};

 

//First method of implementing the constructor for Employee

Employee::Employee(int en, Date& dh)

{

empno = en;

datehired = dh;  //Note that this assumes the Date class provides support for assignment operator.

}

 

//Second method of implementing the constructor for Employee (using the parameter initialization list).

Employee::Employee(int en, Date& dh) :   empno( en),  datehired (dh) {  }

 

The first method requires Date to have a default constructor  and to support the assignment operator, which not all classes do.

The second method constructs the object and initializes the data members, eliminating the need for a Date default constructor and assignment operator.

See Stevens, page 214.

 

Order of Initialization:

point :: point () : y(x), x(0)    //if x was declared before y, then x is initialized first (see Flamig, p 183)

{

return

}

Try not  rely on the order that member objects are initialized when using member initialization lists. If you find yourself relying on that order, you might want to rethink the design of your class.

Back to top

 

Pointers

 

The this pointer:

The this pointer exists for a class whenever a non-static member function is executing. It points to a specific object of the class at hand - specifically, it points to the object for which the member function is executing.  Whenever a member function is called by the program for a specific object, then that member function is passed the this pointer, and that pointer points to that specific object.

Every reference to any member of the class from within a member function of that same class,  implicitly uses the this pointer. Nonetheless, you may also use the this pointer explicitly with the member pointer operator, "->".

Static member functions have no access to non-static member data, and as a consequence have no need for the this pointer and cannot use it.

Since the this pointer is available to a member function, it can be passed by value to any other function in the program that needs the address of the object, or it can be returned the caller of the function as a return value.

 

Points on pointers (from Stevens, page 121):

int i, j;                  //int variables

int* ip;                 //pointer to an int variable

ip = &i;      //assign address of int variable to pointer to int

j = *ip;                  //retrieve int that int pointer points to (also called "de-referencing" ip)

int**  ipp;   //pointer to int pointer

ipp &ip;     //assign address of pointer - now ipp holds the address of ip, which is the pointer to int

j = **ipp      //retrieve int through pointer to int pointer (also called "de-referencing the result of de-referencing the pointer to the pointer)

 

Pointers to const:                   Example – const char* str; //declaration of a pointer that points to a const. Such a pointer cannot be used to modify the const variable.

const Pointer Variables:        Example – char* const ptr = buf; //declaration of a pointer that is, itself, const and points to a char. Such a pointer cannot be modified, but does not affect whether or not the char that it points to can be modified through the pointer.

void Pointers:                        Example – void* vptr;  //useful for overriding the operator new.

 

 

 

The spaces are ignored by the compiler, but the style shown is favored by C++ programmers.

 

Back to top

 

Private Classes

Private classes are classes with private constructors. Only members and friends can instantiate objects from a private class.

Back to top

 

Qualifiers

const: 

When applied to data, the  const qualifier prohibits re-assignment from the initialized value. When applied to functions, the const qualifier prohibits the function from modifying any data.  C programmers might be more likely to use the #define to create a symbol with a value.  Even though a const variable seems to be an oxymoron, that is only so because we use the term variable when we probably need a better word to describe the stored data entities. An object might be declared const because you do not want its data members to be modified - i.e., you want them to be as if they were constants themselves. 

volatile:

Volatile is a warning to the compiler that the program may be changing the variable in unseen ways. It tells the compiler not to make optimizations on the variable.

Consider the ramifications of multi-threaded programs or interrupt service routines that involve asynchronous execution paths through the code.

Back to top

 

Reference Data Members

 

Reference data members must be initialized with the constructor's parameter initialization list - see above!

 

Back to top

 

Storage Classes

auto:

Local variables are auto by default. Use of the keyword is  optional. Function parameters are auto by default unless they are declared to be register. Auto  variables are also known as "stack" variables, because they are kept on the stack (as are function arguments) instead of main memory.

 

static:

For local variables, it means a scope limited to the block that it is in. The static class is different from auto in that it retains its value between executions of the statement block. Any initializers are effective on the first execution only.  For variables outside of any statement block or function, the scope is the entire file. An additional implication of static as a storage class is that it is invisible to the linker – i.e., it cannot be referenced from outside of its translation unit. Stevens, page 94.

extern:

Declares external variables that haven't yet been defined. Typically, those variables are located in another translation unit. There may be several declarations of an extern variable. The location where the declaration occurs determines the scope. If it is made within a function, then it can only be referenced from within that function. If it appears outside of any function, then it can be referenced from any function that follows the declaration in that translation unit.

 

register:

Same as auto except that the compiler is being allowed to put the variable into a register (if it chooses to). It is not appropriate to take the address of a register variable, since a register has no address.

 

Back to top

 

Templates

Specification of a Class Template:

template <class T>      //The ”T” identifier represents the parameterized data type throughout the definition.

class LinkedList   {      //”LinkedList” is the generic class that will be used as the container for LinkedList objects that can be any one of several different data types.

            T&  p;               //Declares a reference to the parametized data type called “p”

//…

public:

            //…

void AddEntry(T  &entry);      //Member function AddEntry takes a reference to the parametized data type and adds it to the linked list.

};

 

When the AddEntry function is implemented, it too must be identified with the template, as follows:

template <class T>

void LinkedList<T> :: AddEntry(T  &entry)

{

            //…

}

 

Both the implemented member function(s) and the specification of the template should be placed in a header file and made visible to any program that will declare objects of that class, as follows:

LinkedList<int>   IntList;   //Where the data type inside the “< > “ specifies the data type which replaces  the parameter “T” in the a above sample specification, and the name IntList is the name of the object being instantiated from the class LinkedList. Note that the object being created is not an “int” – rather it is a linked-list of “int”, albeit an empty list.

 

Note that the parametized data type in the “< >” can also be a list of different data types – i.e., you are not limited to one argument when you design a template.

Function Templates:

A template can define a parameterized non-member function, as follows:

template <class T>

T& min(T& a, T& b)

{

            return (a < b ? a : b);

}

Templates and Abstraction: See Stevens, pages 350-1.

Back to top

 

Text References:

Al Stevens, Teach Yourself C++, 6th Edition, IDG Books, ISBN 0-7645-4634-1

Ivor Horton, Beginning Visual C++ 6, WROX Press, ISBN 1-861000-88-X

Jesse Liberty, Sams Teach Yourself C++ in 21 Days, Third Edition, Sams Publishing, ISBN 0-672-31515-7

Bryan Flamig, Turbo C++,  A Self Teaching Guide, Wiley, ISBN 0-471-52903-6

Back to top

 

TypeCasting and Type Conversions

Rules for conversions between numeric types (char, int, long integers, and float):

            “Up” casts are made without any loss of information.

“Down” casts may cause a loss of information, and the compiler should give a warning to that effect.

If a “down” cast is made using typecasts, there is no difference in whether or not there will be truncation, only that the compiler now assumes that you know what you are doing and does not give a warning.

.

Back to top

 

Virtual Base Classes

Rules for Virtual Base Classes:

A class with a constructor and parameters cannot be a virtual base class.

A virtual base class will be declared as virtual in the declarations of its derived classes.

A pointer to a virtual base class cannot be cast to a class that is descended from it.

 

Back to top