Something about C/C++

Notice:I am learning C++ and I write down this artical just want to prevent me form forgetting.Reproduced,please indicate the source! 

With the exception of static const int data members , a class’s data members cannot be initialized where they’re declared in the class body.

Objects contain only data, so objects are much smaller than if they also contained member functions. Applying operator sizeof to a class name or to an object of that class will report only the size of the class’s data members. The compiler creates one copy (only) of the member functions separate from all objects of the class. All objects of the class share this one copy.
Each object, of course, needs its own copy of the class’s data, because the data can vary among the objects. The function code is nonmodifiable and, hence, can be shared among all objects of one class.

 


 Char 

2013-04-25  11:41:01

1     char a,b,c;
2     a='a';
3     b='\x61';//Hexadecimal.
4     c='\141';//Octonary.
5     printf("%d\ ",(unsigned int)a);
6     printf("%d\ ",(unsigned int)b);
7     printf("%d\ ",(unsigned int)c);
8     //output:97 97 97
 1 #include <stdio.h>
 2  
 3  int main()
 4  {
 5      unsigned char uc;
 6      char c;
 7      uc = 0x81;
 8      c = uc;
 9      printf("c=%d\n",c);//-127
10      printf("uc=%d\n",uc);//129
11  
12      //sign extension with '1'
13      printf("%x\n",(unsigned int)c);//ffffff81
14      //sign extension with '0'
15      printf("%x\n",(unsigned int)uc);//81
16      //implicit type conversion
17      printf("%x\n",(unsigned char)c);//81
18  
19  }

Treated as different types 

"arm-linux-gcc" treats type char as "unsigned char" and "gcc" treats it as "signed char",so the below syntax blocks will get the same result.

1 unsigned char DecodeProtocol(unsigned char *pu8DataRx, unsigned char *pu8Data, unsigned char *pu8Length);
2 //'signed char'='unsigned char' when using 'x86 gcc'.
3 //'unsigned char'='unsigned char' when using 'arm-linux-gcc'.
4 char u8RetValue = DecodeProtocol(msgBuffer,au8RxDataToRead, &u8Length);

 


Pointer

There are three values that can be used to initialize a pointer: 0, NULL(but in C++, 0 is used by convention) or an address of an object of the same type. The new C++ standard also provides the nullptr constant, which is preferred.The only integer that can be assigned to a pointer without casting is zero.The value 0 is the only integer value that can be assigned directly to a pointer variable without first casting the integer to a pointer type.

If a value does not (or should not) change in the body of a function to which it’s passed,the parameter should be declared const.By default, objects are passed by value—a copy of the entire object is passed. This requires the execution-time overhead of making a copy of each data item in the object and storing it on the function call stack. When a pointer to an object is passed, only a copy of the address of the object must be made—the object itself is not copied.

 Type of Void

All pointer types can be assigned to a pointer of type void * without casting. However, a pointer of type void * cannot be assigned directly to a pointer of another type—the pointer of type void * must first be cast to the proper pointer type.

So,in a function parameter,it is helpful to declare any pointer as type void.such as:

bool readFile(const char * _fileName,void * _pBuf,int _bufLen);

Then we can call this function by passing any type of pointer to it without casting.

char buf[32];
readFile(fileName,buf,sizeof(buf));

String literals

String literals have static storage class (they exist for the duration of the program) and may or may not be shared if the same string literal is referenced from multiple locations in a program. The effect of modifying a string literal is undefined; thus, you should always declare a pointer to a string literal as const char *.

1 char aChar[]="blue";
2 //this statement has the same effect with the above statement.
3 char aChar[]={'b','l','u','e','\0'};
4 //the effect of modifying a string literal is undefined,
5 //so you should always declare a pointer to string literal as 'const char *'.
6 const char * csPtr="blue";

Command-line Arguments

String arrays are commonly used with command-line arguments that are passed to function main when a program begins execution.Each pointer points to the first character of its corresponding string.

1 const char * const suit[4]={"Hearts", "Diamonds", "Clubs", "Spades"};
2 int main(int argc,char * argv[]);
3 int main(int argc,char ** argv);

 Selection Sort:

SelectionSort.cpp
 1 #include <iostream>
 2 using namespace std;
 3 
 4 //the first parameter can alse be declared as 'int array[]'
 5 //the type of a array name is 'a const pointer to nonconstant type'
 6 void selectionSort(int * const array,const int len);
 7 void swap(int * const a,int * const b);
 8 void printArray(int * const array,const int len);
 9 
10 int main()
11 {
12     const int size=10;
13     int aInt10[size]={12,32,15,6,54,73,32,75,5,50};
14     printArray(aInt10,size);
15     selectionSort(aInt10,size);
16     printArray(aInt10,size);
17 }
18 
19 void selectionSort(int * const array,const int len)
20 {
21     int smallest;
22     
23     for(int i=0;i<len-1;++i)
24         {
25         smallest=i;
26         for(int index=i+1;index<len;++index)
27             {
28             if(array[index]<array[smallest])
29                 {
30                 smallest=index;
31             }
32         }
33 
34         swap(&array[i],&array[smallest]);
35     }
36 }
37 
38 void swap(int * const a,int * const b)
39 {
40     int tmp;
41     tmp=*a;
42     *a=*b;
43     *b=tmp;
44 }
45 
46 void printArray(int * const array,const int len)
47 {
48     for(int index=0;index<len;++index)
49         {
50         cout<<array[index]<<"\t";
51     }
52     cout<<endl;
53 }

 


Array & Vector

Array

Arrays, structures and classes are “static” entities in that they remain the same size throughout program execution.The ISO/IEC C++ standard defines an “object” as any “region of storage.” Like objects of classes, fundamental-type variables also occupy space in memory, so they’re often referred to as “objects.”

 1 //use initializer list to initialize array n
 2 int n[10] = {21,42,53,74,23,64,75,97,23,43};
 3 
 4 //If there are fewer initializers than array elements,the 
 5 //remaining array elements are initialized to zero.
 6 int n[10] ={};
 7 
 8 //If the array size is omitted from a declaration with an initializer list
 9 //the compiler sizes the array to the number of elements in the initializer list.
10 int n[]={1,2,3,4,5}; 
11 
12 //constant variable can be used to specify array size
13 const int arraySize=10;
14 int s[arraySize]={};
15 
16 void func(void)
17 {
18     //if a static array is not initialized explicitly
19     //when they are declared,each element of that array
20     //is initialized to zero by the complier.But auto arrary 
21     //is not.
22     static int staticArray[3];
23     int autoArray[3];
24 }
25 
26 void constArgumentArray(const int b[])
27 {
28     //array 'b' can not be modified within this 
29     //function body when argument 'b' has a qualifier 'const'
30 }
31 
32 int array1[2][3]={{1,2,3},{4,5,6}};
33 int array2[2][3]={1,2,3,4,5};
34 int array3[2][3]={{1,2},{2}};
35 
36 //determine the number of elements in an array.
37 double aReal[10];
38 int nElements=sizeof(aReal)/sizeof(aReal[0]);
Insertion Sort
 1 #include <iostream>
 2 
 3 void insertionSort(int aInt[],int aIntSize);
 4 void printArray(int aInt[],int aIntSize);
 5 
 6 int main()
 7 {
 8     const int aIntSize=10;
 9     int aInt[10]={23,43,56,87,89,56,12,56,64,71};
10     printArray(aInt,10);
11     insertionSort(aInt,10);
12     printArray(aInt,10);    
13 }
14 
15 void insertionSort(int aInt[],int aIntSize)
16 {
17     int insert;
18     int moveItem;
19     
20     for(int i=1;i<aIntSize;++i)
21         {
22         insert=aInt[i];
23         moveItem=i;
24         
25         while(0<moveItem && aInt[moveItem-1]>insert)
26             {
27                                                 //need to be attention here
28             aInt[moveItem]=aInt[moveItem-1];
29             --moveItem;
30         }
31         aInt[moveItem]= insert;
32     }
33 }
34 
35 void printArray(int aInt[],int aIntSize)
36 {
37     for(int i=0;i<aIntSize;++i)
38         {
39         std::cout<<aInt[i]<<"\t";
40     }
41     std::cout<<std::endl;
42 }

When a function receives a one-dimensional array as an argument, the array brackets are empty in the function’s parameter list. The size of a two-dimensional array’s first dimension (i.e., the number of rows) is not required either, but all subsequent dimension sizes are required. The compiler uses these sizes to determine the locations in memory of elements in multidimensional arrays. All array elements are stored consecutively in memory, regardless of the number of dimensions. In a two-dimensional array,row 0 is stored in memory followed by row 1. Each row is a one-dimensional array. To locate an element in a particular row, the function must know exactly how many elements are in each row so it can skip the proper number of memory locations when accessing the array. Thus, when accessing a[1][2], the function knows to skip row 0’s three elements in memory to get to row 1. Then, the function accesses element 2 of that row.

Dimensional Array
 1 #include <iostream>
 2 
 3 void printDimenIntArray(int aIntDimen[][3]);
 4 
 5 int main()
 6 {
 7     int aIntDimensinal[][3]={{1,2,3},{4,5,6}};
 8     printDimenIntArray(aIntDimensinal);
 9 }
10 
11 void printDimenIntArray(int aIntDimen[][3])
12 {
13     for(int i=0;i<2;i++)
14         {
15         for(int j=0;j<3;j++)
16             {
17             std::cout<<aIntDimen[i][j]<<"\t";
18         }
19         std::cout<<std::endl;
20     }
21 }

 Vector

 Introduce to Vector 

  


Function

Evaluation Order of Function Arguments

The order of evaluation of a function’s arguments,however, is not specified by the C++ standard. Thus, different compilers can evaluate function arguments in different orders. The C++ standard does guarantee that all arguments in a function call are evaluated before the called function executes.If you have doubts about the order of evaluation of a function’s arguments and whether the order would affect the values passed to the function, evaluate the arguments in separate assignment statements before the function call, assign the result of each expression to a local variable, then pass those variables as arguments to the function.

Return Control

There are three ways to return control to the point at which a function was invoked.If the function does not return a result (i.e., it has a void return type), control returns when the program reaches the function-ending right brace, or by execution of the statement "return;"If the function does return a result, the statement "return expression;"evaluates expression and returns the value of expression to the caller.

Argument Coercion

Sometimes, argument values that do not correspond precisely to the parameter types in the function prototype can be converted by the compiler to the proper type before the function is called.Converting values to lower fundamental types can result in incorrect values. Therefore,a value can be converted to a lower fundamental type only by explicitly assigning the
value to a variable of lower type (some compilers will issue a warning in this case) or by using a cast operator.

Below lists the fundamental data type from "highest type" to "lowest type".

Standard Library Headers

Header names ending in.h are “old-style” headers that have been superseded by the C++ Standard Library headers.

Some common C++ Standard Library headers are listed below:

Case Study:Game of Chance

Random Number Generation
 1 #include <iostream>
 2 //contain prototype for function 'rand()' &'srand()'
 3 #include <cstdlib>
 4 //contain prototype for function 'time()'
 5 #include <ctime>
 6 
 7 using namespace std;
 8 
 9 int rollDice();
10 
11 int main()
12 {
13     //return the current time as the number of seconds since January 1,1970 at midnight GMT.
14     //this is converted to an unsigned int which is used as the seed of the random number generator.
15     srand(time(0));
16     
17     //declare a user-defined type called enumeration
18     //capitalize the first letter of an identifier used as a user-defined type name.
19     //using only upperletters in enumeration constant name can remind you that 
20     //enumeration constants are not variable.
21     enum FinalStatus{WIN,LOSS,CONTINUE};
22     
23     FinalStatus status;
24     int sumOfDice;
25     int myPoint;
26 
27     sumOfDice=rollDice();
28     switch (sumOfDice)
29         {
30         case 7:
31         case 11:
32             status=WIN;
33             break;
34         case 2:
35         case 3:
36         case 12:
37             status=LOSS;
38             break;
39         default:
40             status=CONTINUE;
41             myPoint=sumOfDice;
42             break;
43     }
44 
45     while(status==CONTINUE)
46         {
47         sumOfDice=rollDice();
48         if(myPoint==sumOfDice)
49             status=WIN;
50         else if(7==sumOfDice)
51             status=LOSS;
52     }
53 
54     if(WIN==status)
55         cout<<"you win the game"<<endl;
56     else
57         cout<<"you loss the game"<<endl;
58     
59 }
60 
61 int rollDice()
62 {
63     //rand() generate an unsigned int  between 0 to RAND_MAX(a symbolic constant 
64     //definded in <cstdlib> header.
65     //function rand() actually generates pseudorandom numbers which repeats itself 
66     //each time the program executes.
67     int die1=1+rand()%6;
68     
69     int die2=1+rand()%6;
70     cout<<"roll result:"<<die1<<"+"<<die2<<"="<<die1+die2<<endl;
71     return die1+die2;
72 }

Inline Function

If a member function is defined in the body of a class definition, the member function is implicitly declared inline. Remember that the compiler reserves the right not to inline any function. Reusable inline functions are typically placed in headers, so that their definitions can be included in each source file that uses them.Placing the qualifier inline before a function’s return type in the function definition “advises” the compiler to generate a copy of the function’s body code in place (when appropriate) to avoid a function call.

 1 #include <iostream>
 2 inline double cube(double a);
 3 
 4 int main()
 5 {
 6     double x=5.1;
 7     std::cout<<"x^3="<<cube(x)<<std::endl;
 8     
 9 }
10 
11 inline double cube(double a)
12 {
13     return a*a*a;
14 }

References and Reference Parameters

For passing large objects, use a constant reference parameter to simulate the appearance and security of pass-by-value and avoid the overhead of passing a copy of the large object.

Reference and Reference Paratemers
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 //A reference parameter is an alias for its coresponding argument in the function call. 
 6 void square(int& intRef);
 7 
 8 int main()
 9 {
10     int x=4;
11     cout<<"Before func call:"<<"x="<<x<<endl;
12     square(x);
13     cout<<"After func call:"<<"x="<<x<<endl;
14 
15     int y=3;
16     //Reference variables must be initialized in their declarations.
17     //and can not be reassigned as aliases to other variables.
18     int& z=y;
19     cout<<"z="<<z<<endl;
20 }
21 
22 void square(int& intRef)
23 {
24     intRef *=intRef;
25 }
26 
27 //output:
28 //Before func call:x=4
29 //After func call:x=16
30 //z=3

 Default Argument

1-When a program omits an argument for a parameter with a default argument in a function call, the compiler rewrites the function call and inserts the default value of that argument.

2-Default arguments must be the rightmost (trailing) arguments in a function’s parameter list.

3-Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype,or might in the function header.

4-Default values can be any expression, including constants, global variables or function calls.

5-Default arguments also can be used with inline functions.

6-Any arguments passed to the function explicitly are assigned to the function’s parameters from left to right.

Function's Default Argument
 1 #include <iostream>
 2 
 3 int volumn(int high=1,int width=1,int length=1);
 4 
 5 int main()
 6 {
 7     int h=10,w=10,l=10;
 8     std::cout<<"volumn(h):"<<volumn(h)<<std::endl;
 9     std::cout<<"volumn(h,w):"<<volumn(h,w)<<std::endl;
10     std::cout<<"volumn(h,w,l):"<<volumn(h,w,l)<<std::endl;
11 }
12 
13 int volumn(int high,int width,int length)
14 {
15     return high*width*length;
16 }

 Unary Scope Operator

C++ provides the unary scope resolution operator (::) to access a global variable when a local variable of the same name is in scope.

Using the unary scope resolution operator (::) with a given variable name is optional when the only variable with that name is a global variable.

Unary Scope Operator
 1 #include <iostream>
 2 
 3 void read();
 4 int scope=10;
 5 
 6 int main()
 7 {
 8     int scope=11;
 9     //this two function call has the same effect.
10     read();
11     ::read();
12 
13     std::cout<<scope<<std::endl;//11
14     std::cout<<::scope<<std::endl;//10
15 }
16 
17 void read()
18 {
19     std::cout<<"I'm in grobal:read"<<std::endl;
20 }

Overload Function

 C++ enables several functions of the same name to be defined, as long as they have different signatures.A signature is a combination of a function’s name and its parameter types (in order). The compiler uses only the parameter lists to distinguish between overloaded functions. Creating overloaded functions with identical parameter lists and different return types is a compilation error.Member functions of a class can be overloaded, but only by other member functions of that class.

The compiler encodes each function identifier with the number and types of its parameters (sometimes referred to as name mangling or name decoration) to enable type-safe linkage.Function-name mangling is compiler specific.Below show the mangled function names produced in assembly language by GNU C++. Each mangled name (other than main) begins with two underscores (__) followed by the letter Z, a number and the function name. The number that follows Z specifies how many characters are in the function’s name.The function name is then followed by an encoding of its parameter list The return types of the functions are not specified in the mangled names. 

 1 int square(int x){return x*x;}
 2 
 3 double square(double y){return y*y;}
 4 
 5 void nothing1( int a, float b, char c, int &d ){}
 6 
 7 int nothing2( char a, int b, float &c, double &d ){return 0;}
 8 
 9 int main()
10 {
11 
12 }
13 
14 //g++ -S overload.cpp -o overload.s
15 //_Z6squarei
16 //_Z6squared
17 //_Z8nothing1ifcRi
18 //_Z8nothing2ciRfRd

Function Template

You write a single function template definition. Given the argument types provided in calls to this function, C++ automatically generates separate function template specializations to handle each type of call appropriately.

 1 #include <iostream>
 2 
 3 //The formal type parameters are placeholders for fundamental types or user-defined
 4 template<typename T>
 5 T findMax(T a,T b,T c)
 6 {
 7     T max;
 8     max = a;
 9     if(b>max)
10         max=b;
11     if(c>max)
12         max=c;
13     return max;
14 }
15 
16 int main()
17 {
18     int a=1,b=2,c=3;
19     double d=1.1,e=1.2,f=1.3;
20     char cha='a',chb='b',chc='c';
21 
22     std::cout<<"Max in 1,2,3 is:"<<findMax(a,b,c)<<std::endl;
23     std::cout<<"Max in 1.1,1.2,1.3 is:"<<findMax(d,e,f)<<std::endl;
24     std::cout<<"Max in a,b,c is:"<<findMax(cha,chb,chc)<<std::endl;
25 }
26 
27 //Max in 1,2,3 is:3
28 //Max in 1.1,1.2,1.3 is:1.3
29 //Max in a,b,c is:c

 


 Class 

Class Scope

Variables declared in a member function have local scope and are known only to that function. If a member function defines a variable with the same name as a variable with class scope, the class-scope variable is hidden by the block-scope variable in the local scope.Such a hidden variable can be accessed by preceding the variable name with the class name followed by the scope resolution operator (::). Hidden global variables can be accessed with the scope resolution operators.

Scope
 1 //scope.cpp
 2 #include <iostream>
 3 using namespace std;
 4 
 5 int variable = 100;
 6 
 7 void boo();
 8 class Foo
 9 {
10 public:
11     static const int variable = 300;
12 };
13 
14 
15 int main()
16 {
17     boo();
18 }
19 
20 void boo()
21 {
22     int variable = 200;
23     cout<<"grobal variable:"<<::variable<<endl;
24     cout<<"function variable:"<<variable<<endl;
25     cout<<"class variable:"<<Foo::variable<<endl;
26 
27 }

 Accessing Class Member

 A class’s data members and member functions belong to that class’s scope. Nonmember functions are defined at global namespace scope.Outside a class’s scope, public class members are referenced through one of the handles on an object—an object name, a reference to an object or a pointer to an object.

Class members access operator
 1 // Demonstrating the class member access operators . and ->
 2 #include <iostream>
 3 using std::cout;
 4 using std::endl;
 5 
 6 // class Count definition
 7 class Count 
 8 {
 9 public: // public data is dangerous
10    // sets the value of private data member x
11    void setX( int value )
12    {
13       x = value;
14    } // end function setX
15 
16    // prints the value of private data member x
17    void print() 
18    { 
19       cout << x << endl; 
20    } // end function print
21 
22 private:
23    int x;  
24 }; // end class Count
25 
26 int main()
27 {
28    Count counter; // create counter object 
29    Count *counterPtr = &counter; // create pointer to counter
30    Count &counterRef = counter; // create reference to counter
31 
32    cout << "Set x to 1 and print using the object's name: ";
33    counter.setX( 1 ); // set data member x to 1
34    counter.print(); // call member function print
35 
36    cout << "Set x to 2 and print using a reference to an object: ";
37    counterRef.setX( 2 ); // set data member x to 2
38    counterRef.print(); // call member function print
39 
40    cout << "Set x to 3 and print using a pointer to an object: ";
41    counterPtr->setX( 3 ); // set data member x to 3
42    counterPtr->print(); // call member function print
43    return 0;  
44 } // end main

Access Functions and Utility function

A utility function is not part of a class’s public interface; rather, it’s a private member function that supports the operation of the class’s other member functions. Utility functions are not intended to be used by clients of a class

SalesPerson.h
 1 #ifndef SALESP_H
 2 #define SALESP_H
 3 
 4 class SalesPerson 
 5 {
 6 public:
 7    SalesPerson(); // constructor
 8    void getSalesFromUser(); // input sales from keyboard
 9    void setSales( int, double ); // set sales for a specific month
10    void printAnnualSales(); // summarize and print sales
11 private:
12    double totalAnnualSales(); // prototype for utility function
13    double sales[ 12 ]; // 12 monthly sales figures
14 }; // end class SalesPerson
15 
16 #endif
SalesPerson.cpp
 1 // Member functions for class SalesPerson.
 2 #include <iostream>
 3 using std::cout;
 4 using std::cin;
 5 using std::endl;
 6 using std::fixed;
 7 
 8 #include <iomanip>
 9 using std::setprecision;
10 
11 #include "SalesPerson.h" // include SalesPerson class definition
12 
13 // initialize elements of array sales to 0.0
14 SalesPerson::SalesPerson()
15 {
16    for ( int i = 0; i < 12; i++ )
17       sales[ i ] = 0.0;
18 } // end SalesPerson constructor
19 
20 // get 12 sales figures from the user at the keyboard
21 void SalesPerson::getSalesFromUser()
22 {
23    double salesFigure; 
24 
25    for ( int i = 1; i <= 12; i++ ) 
26    {
27       cout << "Enter sales amount for month " << i << ": ";
28       cin >> salesFigure;
29       setSales( i, salesFigure );
30    } // end for
31 } // end function getSalesFromUser
32 
33 // set one of the 12 monthly sales figures; function subtracts
34 // one from month value for proper subscript in sales array
35 void SalesPerson::setSales( int month, double amount )
36 {
37    // test for valid month and amount values
38    if ( month >= 1 && month <= 12 && amount > 0 )
39       sales[ month - 1 ] = amount; // adjust for subscripts 0-11
40    else // invalid month or amount value
41       cout << "Invalid month or sales figure" << endl;   
42 } // end function setSales
43 
44 // print total annual sales (with the help of utility function)
45 void SalesPerson::printAnnualSales()
46 {
47    cout << setprecision( 2 ) << fixed 
48       << "\nThe total annual sales are: $" 
49       << totalAnnualSales() << endl; // call utility function
50 } // end function printAnnualSales
51 
52 // private utility function to total annual sales
53 double SalesPerson::totalAnnualSales()
54 {
55    double total = 0.0; // initialize total
56 
57    for ( int i = 0; i < 12; i++ ) // summarize sales results
58       total += sales[ i ]; // add month i sales to total
59 
60    return total;                   
61 } // end function totalAnnualSales
main.cpp
 1 #include "SalesPerson.h"  
 2 
 3 int main()
 4 {
 5    SalesPerson s; // create SalesPerson object s
 6    
 7    s.getSalesFromUser(); // note simple sequential code;
 8    s.printAnnualSales(); // no control statements in main
 9    return 0;
10 } // end main

Constructor

2013-03-23 00:52:31

In C++, the code that runs when an object is declared is called the constructor.Constructor is part of the public section of the class.If the constructor were not public, then no instances of the object could be created.

Const field initialization

If you declare a field of your class as const, then that field must be initialized in the initialization list:

The default arguments to the constructor ensure that, even if no values are provided in a constructor call, the constructor still initializes the data members. A constructor that defaults all its arguments is also a default constructor—that is, a constructor that can be invoked with no arguments. There can be at most one default constructor per class.

View Code
 1 //ConstructorWithDefaultArgument.h
 2 #ifndef __ARGUMENT_H__
 3 #define __ARGUMENT_H__
 4 
 5 class Time{
 6 public:
 7     Time(int =12,int =0,int =0);
 8     void setTime(int h,int m,int s);
 9     int getTime();
10 private:
11     int hour;
12     int minute;
13     int second;
14     
15 };
16 #endif
17 
18 //----------------------------------------------------------------------
19 //ConstructorWithDefaultArgument.cpp
20 #include <iostream>
21 #include "ConstructorWithDefaultArgument.h"
22 using namespace std;
23 
24 Time::Time(int h,int m,int s)
25 {
26     setTime(h,m,s);
27 }
28 
29 void Time::setTime(int h,int m,int s)
30 {
31     hour = h;
32     minute = m;
33     second = s;
34 }
35 
36 int Time::getTime()
37 {
38     int t;
39     t = hour *10000+minute*100+second;
40     cout<<"Here is the time: "<<t<<endl; 
41 }
42 
43 #include "ConstructorWithDefaultArgument.h"
44 
45 //----------------------------------------------------------------------
46 //main.cpp
47 int main()
48 {
49     Time myTime1;
50     Time myTime2(13);
51     Time myTime3(13,14);
52     Time myTime4(13,14,15);
53 
54     myTime1.getTime();
55     myTime2.getTime();
56     myTime3.getTime();
57     myTime4.getTime();
58 }

Having the Time constructor call setTime  enables us to limit the changes to code that validates the hour, minute or second to the corresponding set function. This reduces the likelihood of errors when altering the class’s implementation.

If a member function of a class already provides all or part of the functionality required by a constructor (or other member function) of the class, call that member function from the constructor (or other member function). This simplifies the maintenance of the code and reduces the likelihood of an error if the implementation of the code is modified. As a general rule: Avoid repeating code.

When Constructor and Destructor are called

The order in which these function calls occur depends on the order in which execution enters and leaves the scopes where the objects are instantiated.Generally, destructor calls are made in the reverse order of the corresponding constructor calls.

 A class’s destructor is called implicitly when an object is no longer needs. So what does it actually mean for an object to be "no longer needed"? It means one of three things:
1)  When you delete a pointer to an object
2)  When the object goes out of scope
3)  When the object belongs to a class whose destructor is being called

This occurs, for example, as an automatic object is destroyed when program execution leaves the scope in which that object was instantiated. The destructor itself does not actually release the object’s.memory—it performs termination housekeeping before the object’s memory is reclaimed, so the memory may be reused to hold new objects.If you do not explicitly provide a destructor, the compiler creates an “empty” destructor.It’s a syntax error to attempt to pass arguments to a destructor, to specify a return type for a destructor (even void cannot be specified), to return values from a destructor or to overload a destructor.

When Destructor is called
 1 //Destructor.h
 2  #ifndef __DESTRUCTOR_H__
 3  #define __DESTRUCTOR_H__
 4  
 5  class Destructor
 6  {
 7  public:
 8      Destructor(int n);
 9      ~Destructor();
10  private:
11      int number;
12  };
13  
14  
15  #endif
16  
17  //--------------------------------------------------------------------------
18  //Destructor.cpp
19  #include <iostream>
20  #include "Destructor.h"
21  
22  using namespace std;
23  
24  Destructor::Destructor(int n)
25  {
26      number = n;
27      cout<<"Constructor: object "<<number<<endl;
28  }
29  
30  Destructor::~Destructor()
31  {
32      cout<<"Destructor: object "<<number<<endl;
33  }
34  
35  
36  //--------------------------------------------------------------------------
37  //main.cpp
38  #include "Destructor.h"
39  
40  Destructor myDestructor1(1);
41  void create();
42  
43  int main()
44  {
45      static Destructor myDestructor2(2);
46      Destructor myDestructor3(3);
47      create();
48      Destructor myDestructor4(4);
49  }
50  
51  void create()
52  {
53      Destructor myDestructor5(5);
54      static Destructor myDestructor6(6);
55      Destructor myDestructor7(7);
56  }

Default Memberwise Assignment

2013-03-23  11:40:52

 The assignment operator (=) can be used to assign an object to another object of the same type. By default, such assignment is performed by memberwise assignment—each data member of the object on the right of the assignment operator is assigned individually to the same data member in the object on the left of the assignment operator.

Caution: Memberwise assignment can cause serious problems when used with a class whose data members contain pointers to dynamically allocated memory.

Objects may be passed as function arguments and may be returned from functions. Such passing and returning is performed using pass-by-value by default—a copy of the object is passed or returned. In such cases, C++ creates a new object and uses a copy constructor to copy the original object’s values into the new object. For each class, the compiler provides a default copy constructor that copies each member of the original object nto the corresponding member of the new object.

Passing an object by value is good from a security standpoint, because the called function has no access to the original object in the caller, but pass-by-value can degrade performance when making a copy of a large object. An object can be passed by reference by passing either a pointer or a reference to the object. Pass-by-reference offers good performance but is weaker from a security standpoint, because the called function is given access to the original object. Pass-by-const-reference is a safe, good-performing alternative (this can be implemented with a const reference parameter or with a pointer-to-const-data parameter).

Memberwise Assignment
 1 //DefaultMemberwise.h
 2 #ifndef __DEFAULT_MEMBERWISE_H__
 3 #define __DEFAULT_MEMBERWISE_H__
 4 
 5 class Memberwise
 6 {
 7 public:
 8     Memberwise(int y=2013,int m=3,int d=23);
 9     void getDate();
10 private:
11     int year;
12     int month;
13     int date;
14 };
15 
16 #endif
17 
18 //--------------------------------------------------------------------------
19 //DefaultMemberwise.cpp
20 #include "DefaultMemberwise.h"
21 #include <iostream>
22 using namespace std;
23 
24 Memberwise::Memberwise(int y,int m,int d):year(y),month(m),date(d)
25 {
26     
27 }
28 
29 void Memberwise::getDate()
30 {
31     cout<<"date:"<<    year*10000+month*100+date<<endl;
32 }
33 
34 //-------------------------------------------------------------------------
35 //main.cpp
36 #include "DefaultMemberwise.h"
37 
38 int main()
39 {
40     Memberwise myMemberwise1(2012,12,12);
41     Memberwise myMemberwise2;
42 
43     myMemberwise1.getDate();
44     myMemberwise2.getDate();
45 
46     myMemberwise2=myMemberwise1;
47     myMemberwise2.getDate();
48 }

 

Const Object and Const Member Function

 2013-03-23 20:25:27

 You may use keyword const to specify that an object is not modifiable and that any attempt to modify the object should result in a compilation error.Declaring variables and objects const when appropriate can improve performance—compilers can perform optimizations on constants that cannot be performed on variables.

C++ disallows member function calls for const objects unless the member functions themselves are also declared const. Invoking a non-const member function on a const object is a compilation error.

A member function is specified as const both in its prototype by inserting the keyword const after the function’s parameter list and, in the case of the function definition, before the left brace that begins the function body.The fact that a member function does not modify an object is not sufficient to indicate that the function is a constant function—the function must explicitly be declared const.A const member function can't modify a data member or call a none-const member function.But a const member function can be overloaded with a non-const version. The compiler chooses which overloaded member function to use based on the object on which the function is invoked. If the object is const, the compiler uses the const version. If the object is not const, the compiler uses the non-const version.

Attempting to declare a constructor or destructor const is a compilation error.A constructor must be a non-const member function , but it can still be used to initialize a const object.Invoking a nonconst member function from the constructor call as part of the initialization of a const object is allowed. The “constness” of a const object is enforced from the time the constructor completes initialization of the object until that object’s destructor is called.

All data members can be initialized using member initializer syntax, but const data members and data members that are references must be initialized using member initializers. We’ll also see that member objects must be initialized this way as well.

Declare as const all of a class’s member functions that do not modify the object in which they operate.Declaring such member functions const does offer a benefit,. If the member function is inadvertently written to modify the object, the compiler will issue an error message.

About "Const"
 1 //const.h
 2 #ifndef __CONST_H__
 3 #define __CONST_H__
 4 
 5 class Book
 6 {
 7 public:
 8     Book(int e,int m,int p);
 9     void setData(int e);
10     //Declare as const all if it do not modify the object 
11     void getDate() const;
12     void displayDate();
13 
14 private:
15     int english;
16     //warning ,should better not unless it is static member
17     const int math =96;
18     const int physics;
19     
20 };
21 
22 #endif
23 
24 //--------------------------------------------------------------------------
25 //const.cpp
26 #include <iostream>
27 #include "Const.h"
28 using namespace std;
29 
30 Book::Book(int e,int m,int p):physics(p)
31 {
32 //Invoking a nonconst member function from the constructor
33     setData(e);
34 }
35 
36 void Book::setData(int e)
37 {
38     english =e;
39 }
40 
41 void Book::getDate()const
42 {
43     cout<<"english: "<<english<<endl;
44     cout<<"math:    "<<math<<endl;
45     cout<<"physics  "<<physics<<endl;
46 
47 }
48 
49 void Book::displayDate()
50 {
51     cout<<"english: "<<english<<endl;
52     cout<<"math:    "<<math<<endl;
53     cout<<"physics  "<<physics<<endl;
54 }
55 
56 //-------------------------------------------------------------------------
57 //main.cpp
58 #include "Const.h"
59 
60 int main()
61 {
62     const Book myBook1(93,94,95);
63     Book myBook2(83,84,85);
64 
65     myBook2.getDate();//ok
66     myBook2.displayDate();//ok
67     myBook1.getDate();//ok
68                 //error, displayData() is not const member function
69     //myBook1.displayDate();
70     
71 }

 

Composition

 2013-03-24 10:04:23

 Member objects are constructed in the order in which they’re declared in the class definition (not in the order they’re listed in the constructor’s member initializer list) and before their enclosing class objects are constructed.To confirm in the  program output we see that objects are constructed from the inside out and destroyed in the reverse order, from the outside in.That is the Employee destructor runs first  then the member objects are destructed in the reverse order from which they were constructed. (i.e., the Date member objects are destroyed after the Employee object that contains them).

The compiler provides each class with a default copy constructor that copies each data member of the constructor’s argument object into the corresponding member of the object being initialized.When each of the Employee’s Date member object’s is initialized in the Employee constructor’s member initializer list , the default copy constructor for class Date is called. Since this constructor is defined implicitly by the compiler, it does not contain any output statements to demonstrate when it’s called.So we can't see any output from two objects' constructor of Date.If a member object is not initialized through a member initializer, the member object’s default constructor will be called implicitly.So if we change the Employee's constructor to the form of none initialize the object members explicity,we will see the output form the Date constructor.A compilation error occurs if a member object is not initialized with a member initializer and the member object’s class does not provide a default constructor.

Composition
 1 //-------------------------------------------------------------------------
 2 //composition_date.h
 3 #ifndef __COM_DATE_H__
 4 #define __COM_DATE_H__
 5 using namespace std;
 6 
 7 class Date
 8 {
 9 public:
10     Date(int year=2012,int month=12,int day=12);
11     ~Date();
12     //void setData(int year,int month,int day);
13     //void getData() const;
14 private:
15     int year;
16     int month;
17     int day;
18 };
19 
20 
21 
22 #endif
23 
24 
25 //-------------------------------------------------------------------------
26 //composition_date.cpp
27 #include <iostream>
28 #include "composition_date.h"
29 using namespace std;
30 
31 Date::Date(int year, int month ,int day)
32             :year(year),month(month),day(day)
33 {
34     cout<<"Date Constructor: "<<year<<"/"<<month<<"/"<<day<<endl;    
35 }
36 
37 Date::~Date()
38 {
39 
40     cout<<"Date Destructor: "<<year<<"/"<<month<<"/"<<day<<endl;
41 }
42 
43 //-------------------------------------------------------------------------
44 //composition_employee.h
45 #include "composition_date.h"
46 #include <iostream>
47 using namespace std;
48 
49 class Employee
50 {
51 public:
52     Employee(string,string,const Date &);
53     ~Employee();
54 private:
55     string firstName;
56     string lastName;
57     Date birthDate;
58     Date employDate;
59 };
60 
61 
62 //-------------------------------------------------------------------------
63 //composition_employee.cpp
64 #include "composition_date.h"
65 #include "composition_employee.h"
66 #include <iostream>
67 using namespace std;
68 
69 Employee::Employee(string firstN,string lastN,const Date & birthD)
70             :firstName(firstN),lastName(lastN),birthDate(birthD)
71 {
72     cout<<"employee contructor"<<endl;
73 }
74 
75 Employee::~Employee()
76 {
77     cout<<"employee destructor"<<endl;
78 }
79 
80 
81 //-------------------------------------------------------------------------
82 //main.cpp
83 #include <iostream>
84 #include "composition_date.h"
85 #include "composition_employee.h"
86 using namespace std;
87 
88 int main()
89 {
90     Date bD(2012,1,1);
91     Date eD(2013,3,3);
92     cout<<endl;
93     
94                 //There are actually five constructor call.
95     Employee myEmployee("benson","huang",bD);
96     
97     cout<<endl;
98     cout<<"main exit..."<<endl;
99 }

Friend

 2013-03-25 13:12:34

A friend function of a class is defined outside that class’s scope, yet has the right to access the non-public (and public)members of the class.Standalone functions, entire classes or member functions of other classes may be declared to be friends of another class.

To declare a function as a friend of a class,precede the function prototype in the class definition with keyword friend.To declare all member functions of class ClassTwo as friends of class ClassOne,place a declaration of the form in the definition of class ClassOne.

friend class ClassTwo;                     

Member access notions of private, protected and public are not relevant to friend declarations,so friend declarations can be placed anywhere in a class definition. Place notice that it is better to all friendship declarations first inside the classdefinition’s body and do not precede them with any access specifier.

Friendship is granted, not taken. Also, the friendship relation is neither symmetric nor transitive;i.e., if class A is a friend of class B,and class B is a friend of class C, you cannot infer that class B is a friend of class A , that class C is a friend of class B , or that class A is a friend of class C .

friend
 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Year
 5 {
 6 friend void setYear(Year &,int);
 7 public:
 8     int getYear(){return year;}
 9 private:
10     int year;
11 };
12 
13 void setYear(Year & oYear,int y);
14 
15 int main()
16 {
17     Year oYear;
18     int thisYear = 2013;
19     cout<<"Before setting,this year is: "<<oYear.getYear()<<endl;
20     setYear(oYear,thisYear);
21     cout<<"After setting,this year is: "<<oYear.getYear()<<endl;
22 }

This

Every objecthas ac-cess to itsown address through apointercalled this (a C++keyword). The this pointer is not part of the object itself—i.e.,the memory occupiedbythe this pointerisnot re-flectedinthe result of a sizeof operation on theobject.The typeofthe this pointer depends on thetype of the object and whether the member function in which this is used is declared const.For example,in a nonconstant member function of class Employee,the this pointer hastype Employee *const (a constant pointer to a nonconstant Employee object). In aconstant member function of theclass Employee,the this pointerhas the data type const Employee *const (a constant pointer to a constant Employee object).Another use of the this pointer is to enable cascaded member-function calls—that is, invoking multiple functions in the same statement.

this
 1 //this.h
 2 #ifndef __THIS_H__
 3 #define __THIS_H__
 4 
 5 class Time
 6 {
 7 public:
 8     Time(int=0,int=0,int=0);
 9     Time & setTime(int,int,int);
10     void printTime()const;
11 private:
12     int hour;
13     int minute;
14     int second;
15 };
16 
17 #endif
18 
19 
20 //--------------------------------------------------------------------------
21 //this.cp
22 #include <iostream>
23 #include <iomanip>
24 #include <stdexcept>
25 #include "this.h"
26 using namespace std;
27 
28 Time::Time(int hour,int minute,int second)
29 {
30     setTime(hour,minute,second);
31 }
32 
33 Time& Time::setTime(int h,int m,int s)
34 {
35     if(h>=0 && h <=24)
36         hour =h;
37     else
38         throw invalid_argument("hour:1~24");
39 
40     if(m>=0 && m<=59)
41         minute = m;
42     else
43         throw invalid_argument("minute:1~59");
44 
45     if(s>=0 && s<=59)
46         second = s;
47     else
48         throw invalid_argument("second:1~59");
49 
50     return *this;
51 }
52 
53 void Time::printTime()const
54 {
55     cout<<"Time: "<<setfill('0')<<setw(2)<<( (hour ==0 || hour==12)?12:hour%12 )<<":"
56         <<setfill('0')<<setw(2)<<minute<<":"<<setfill('0')<<setw(2)<<second
57         <<" "<<(hour<12 ? "am":"pm")<<endl;
58 }
59 
60 //--------------------------------------------------------------------------
61 //main.cpp
62 
63 #include "this.h"
64 
65 int main()
66 {
67     Time time;
68     time.printTime();
69     time.setTime(14,7,28).printTime();
70 }

 


C File Processing

Data Hierarchy

The smallest data item in a computer can assume the value 0 or the value 1. Such a data item is called a bit.Just as characters are composed of bits, fields are composed of characters. A field is a group of characters that conveys meaning.A record (i.e., a struct in C) is composed of several fields.A group of related files is sometimes called a database. A collection of programs designed to create and manage databases is called a database management system (DBMS).

To facilitate the retrieval of specific records from a file, at least one field in each record is chosen as a record key. A record key identifies a record as belonging to a particular person or entity.There are many ways of organizing records in a file. The most popular type of organization is called a sequential file, in which records are typically stored in order by the
record key field. 

Files and Streams

C views each file simply as a sequential stream of bytes . Each file ends either with an end-of-file marker or at a specific byte number recorded in a system-maintained,administrative data structure. When a file is opened, a stream is associated with the file.Three files and their associated streams are automatically opened when program execution begins—the standard input, the standard output and the standard error. Streams provide communication channels between files and programs.Opening a file returns a pointer to a FILE structure (defined in <stdio.h>) that contains information used to process the file. This structure includes a file descriptor, i.e., an index into an operating system array called the open file table. Each array element contains a file control block (FCB) that the operating system uses to administer a particular file. The standard input, standard output and standard error are manipulated using file pointers stdin, stdout and stderr.

1 //equivalent
2 fgetc(stdin);
3 getchar();
4 
5 //equivalent
6 fputc('a',stdout);
7 putchar('a');

 


New & Delete 

The object or array is created in the free store (also called the heap)—a region of memory assigned to each program for storing dynamically allocated objects.

New 

The new operator allocates storage of the proper size for an object of type Time, calls the default constructor to initialize the object and returns a pointer to the type specified to the right of the new operator (i.e., a Time *). If new is unable to find sufficient space in memory for the object, it indicates that an error occurred by throwing an exception.The keyword new is used to initialize pointers with memory form free store.

int * pInt = new int;
Time * poTime = new Time();

The code that uses pInt must eventually return this memory back to the free store,an operation called freeing the memory. To return the memory back to free store,you use the delete keyword.The delete operation frees up the memory allcoted through new.This statement first calls the destructor for the object to which timePtr points, then deallocates the memory associated with the object, returning the memory to the free store.

delete pInt;
pInt=NULL;

delete poTime;
poTime=NULL;

You can dynamically allocate an array of memory using new and assign the memory to a pointer.The size of an array created at compile time must be specified using a constant integral expression; however, a dynamically allocated array’s size can be specified using any non-negative integral expression that can be evaluated at execution time. Also, when allocating an array of objects dynamically, you cannot pass arguments to each object’s constructor—each object is initialized by its default constructor. For fundamental types, the elements are initialized to 0 or the equivalent of 0 (e.g., chars are initialized to the null character, '\0').

int * paInt = new int[8];

If the pointer points to an array of objects, the statement first calls the destructor for every object in the array, then deallocates the memory. If the preceding statement did not include the
square brackets ([]) and gradesArray pointed to an array of objects, the result is undefined.
Some compilers call the destructor only for the first object in the array. Using delete on a null pointer (i.e., a pointer with the value 0) has no effect.

1 int gradeArray[] = new int[10];
2 delete [] gradeArray;

Delete

Now you can use paInt just as if it pointed to an array.Unlink array,though,you need to free the memory pointed to by paInt,whereas ,you never want to free a pointer pointing to a statically declared array.The brackets tell the compiler that the pointer points to an array of values rather than a signal value.

delete[] paInt;

'delete' and 'delete[]' are different if the type of the array is 'class T',but the same with primitive type.

delete & delete[]
 1 #include <iostream>
 2 using namespace std;
 3 
 4 class T
 5 {
 6 public:
 7     T()
 8     {
 9         count++;
10         cout<<"constructor: "<<count<<endl;
11 
12     }
13     ~T()
14     {
15         cout<<"destructor: "<<count<<endl;
16         --count;
17     }
18 private:
19     static int count;
20 };
21 
22 int T::count=0;
23 
24 
25 int main()
26 {
27     const int size = 3;
28     T * mInstance=new T[size];
29     //only free the memory occupied by mInstance[0]
30     delete mInstance;
31 
32     T * mInstance_1=new T[size];
33     //free the memory occupied by mInstance_1[0] mInstance_1[1] mInstance_1[2]
34     delete[] mInstance_1;
35 }

Use Case 

Reallocate the memory as the value grow.
 1 #include <iostream>
 2 #include <cstring>
 3 #include <stdio.h>
 4 
 5 using namespace std;
 6 
 7 int * growArray(int * pointer,int *pSize);
 8 
 9 int main()
10 {
11     int size=3;
12     int * pointer=new int[size];
13     memset(pointer,0,size*sizeof(int));
14     int nextElement=0;
15     int val;
16 
17     cout<<"Please enter integer number:\n"<<endl;
18     cin>>val;
19 
20     while(0!=val)
21     {
22         //if the array's size is not enough,enlarge the array.
23         if(size==nextElement)
24         {
25             pointer=growArray(pointer,&size);
26         }
27 
28         pointer[nextElement]=val;
29         ++nextElement;
30         cout<<"Please enter integer number(or 0 to exit):\n"<<endl;
31         cin>>val;
32     }//End of while.
33 
34     //print out the int array after the user enter '0'
35     cout<<"the int array you enter is:"<<endl;
36     for(int i=0;0!=pointer[i];++i)
37     {
38         cout<<pointer[i]<<"  "<<endl;
39     }//End of print int array.
40 
41 }//End of function main.
42 
43 int * growArray(int * pointer,int *pSize)
44 {
45     int size=*pSize;
46     int newSize=size*2;
47     *pSize *=2;
48     int * newPointer=new int[newSize];
49     memset(newPointer,0,newSize*sizeof(int));
50 
51     for(int i=0;i<size;++i)
52     {
53         newPointer[i]=pointer[i];
54     }
55     //'delete pointer' is also ok,because pointer points to an array of primitive type.
56     delete[] pointer;
57     return newPointer;
58 }

 


Inheritance & Polymorphism

Base classes and derived classes

With multiple inheritance, a derived class inherits from two or more (possibly unrelated) base classes.Each arrow in the hierarchy (Fig. 12.2) represents an is-a relationship.CommunityMember is the direct base class of Employee, Student and Alumnus. In addition, CommunityMember is an indirect base class of all the other classes in the diagram.

With all forms of inheritance, private members of a base class are not accessible directly from that class’s derived classes, but these private base-class members are still inherited.With public inheritance, all other base-class members retain their original member access when they become members of the derived class(e.g., public members of the base class become public members of the derived class, and,as we’ll soon see, protected members of the base class become protected members of the

derived class).

class Apple:public Shape
{
  
};

Relationship between SubClass and SuperClass

Derived-class member functions can refer to public and protected members of the base class simply by using the member names.When a derived-class member function redefines a base-class member function, the base-class member can still be accessed from the derived class by preceding the base-class member name with the base-class name and the scope resolution operator (::).

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Book
 6 {
 7 public:
 8     void cover();
 9 };
10 
11 void Book::cover()
12 {
13     cout<<"SuperClass:cover()"<<endl;
14 }
15 
16 class Physical:public Book
17 {
18 public:
19     void cover();
20 };
21 
22 void Physical::cover()
23 {
24     //base class member function can still be accessed.
25     Book::cover();
26     cout<<"SubClass:cover()"<<endl;
27 }
28 
29 int main()
30 {
31     Physical myPhysical;
32     //output:"SuperClass:cover()"
33     //       "SubClass:cover()"
34     myPhysical.cover();
35 }

C++ requires that a derived-class constructor call its base-class constructor to initialize the base-class data members that are inherited into the derived class.If Subclass’s constructor did not invoke Super Class's constructor explicitly, C++ would attempt to invoke SuperClass’s default constructor implicitly—but if the SuperClass does not have such a constructor, so the compiler would issue an error.

Constructor and Destructor in Derived Classes

When a program creates a derived-class object, the derived-class constructor immediately calls the base-class constructor, the base-class constructor’s body executes, then the derived class’s member initializers execute and finally the derived-class constructor’s body executes. This process cascades up the hierarchy if it contains more than two levels.

When a derived-class object’s destructor is called, the destructor performs its task, then invokes the destructor of the next base class up the hierarchy. This process repeats until the destructor of the final base class at the top of the hierarchy is called. Then the object is removed from memory.

#include <iostream>
#include <string>

using namespace std;

class Book
{
public:
    //self-define constructor,and there is no default constructor in the class.
    Book(const string & strRef);
    ~Book();
};

Book::Book(const string & strRef)
{
    cout<<"constructor Book:"<<strRef<<endl;
}

Book::~Book()
{
    cout<<"Destructor Book"<<endl;
}

class Physical:public Book
{
public:
    Physical(const string & strRef);
    ~Physical();
};

//call the superclass's constructor in the initialization list.
//if we do not call that constructor,we will get a compile which fail
//to call Book::Book();
Physical::Physical(const string & strRef):Book(strRef)
{
    cout<<"Constructor Physical"<<endl;
}

Physical::~Physical()
{
    cout<<"Destructor Physical"<<endl;
}

int main()
{
    Physical * myPhysical = new Physical("benson");
    delete myPhysical;
    while(true);
}
//output::
//constructor Book:benson
//Constructor Physical
//Destructor Physical
//Destructor Book

Public,Protected and Private Inheritance

When deriving a class from a base class, the base class may be inherited through public,protected or private inheritance.Figure 12.16 summarizes for each type of inheritance the accessibility of base-class members in a derived class.

 Invoking Base-Class functions from Derived-Class

Invoking a function via the base-class pointer invokes the base-class functionality in the derived-class object—i.e., the type of the handle determines which function is called.

 1 #include <iostream>
 2 
 3  using namespace std;
 4 
 5  class Book
 6  {
 7  public:
 8      void cover();
 9      virtual void cost();
10  };
11 
12  void Book::cover()
13  {
14      cout<<"SuperClass:cover()"<<endl;
15  }
16 
17 void Book::cost()
18 {
19     cout<<"cost() in Book"<<endl;
20 }
21 
22  class Physical:public Book
23  {
24  public:
25      void cover();
26      virtual void cost();
27      void page();
28  };
29 
30  void Physical::cover()
31  {
32      cout<<"SubClass:cover()"<<endl;
33  }
34 
35 void Physical::cost()
36 {
37     cout<<"cost() in Physical"<<endl;
38 }
39 
40  void Physical::page()
41  {
42      cout<<"SubClass:page()"<<endl;
43  }
44 
45  int main()
46  {
47     //Base-Class pointer point to Derived-Class.
48     Book * poBook=new Physical();
49     poBook->cover();//SuperClass:cover()
50 
51     //if a base-class pointer is aimed at a derived-class object, and an attempt is
52     //made to access a derived-class-only member function, a compilation error will occur.
53     poBook->page();//error
54 
55     //if we explicitly cast the base-class pointer to
56     //a derived-class pointer—this is known as downcasting,we can
57     //access to derived-class-only members.
58     ((Physical *)poBook)->page();
59 
60     //Derived-Class pointer point to Base-Class will get an compiler error.
61     Physical * poPhysical = new Book();//error
62 }

Virtual Functions

From an implementation perspective, overriding a function is no different than redefining one. An overridden function in a derived class has the same signature and return type (i.e., prototype) as the function it overrides in its base class. If we do not declare the base-class function as virtual, we can redefine that function. By contrast, if we declare the base-class function as virtual, we can override that
function to enable polymorphic behavior.

If a program invokes a virtual function through a base-class pointer to a derivedclass object or a base-class reference to a derived-class object, the program will choose the correct derived-class draw function dynamically (i.e., at execution time) based on the object type—not the pointer or reference
type. Choosing the appropriate function to call at execution time (rather than at compile time) is known as dynamic binding or late binding.

int main()
{
    //Base-Class Book's cost() function is override by the Derived-Class function
    poBook->cost();//output:'cost() ins Physical'

    //dynamic binding with virtual functions occurs only off
    //pointer as well as reference handles.
    Physical myPhysical;
    Book & bookRef=myPhysical;
    bookRef.cost();//output:'cost() ins Physical'
}

Abstract Classes and Pure Virtual Functions

There are cases in which it’s useful to define classes from which you never intend to instantiate any objects. Such classes are called abstract classes. Because these classes normally are used as base classes in inheritance hierarchies, we refer to them as abstract base classes.These classes cannot be used to instantiate objects,classes that can be used to instantiate objects are called concrete classes.

A class is made abstract by declaring one or more of its virtual functions to be “pure.” A pure virtual function is specified by placing “= 0” in its declaration, Pure virtual functions do not provide implementations. Every concrete derived class must override all base-class pure virtual functions with concrete implementations of those functions.

virtual void draw() const = 0; // pure virtual function

The difference between a virtual function and a pure virtual function is that a virtual function has an implementation and gives the derived class the option of overriding the function; by contrast, a pure virtual function does not provide an implementation and requires the derived class to override the function for that derived class to be concrete; otherwise the derived class remains abstract

Simple Polymorphism 

 1 #include <iostream>
 2 #include <vector>
 3 
 4 using namespace std;
 5 
 6 class Shape
 7 {
 8 public:
 9     virtual void draw()=0;
10 };
11 
12 class Apple:public Shape
13 {
14 public:
15     virtual void draw()
16     {
17         cout<<"Draw Apple."<<endl;
18     }
19 };
20 
21 class Pear:public Shape
22 {
23     virtual void draw()
24     {
25         cout<<"Draw Pear."<<endl;
26     }
27 };
28 
29 int main()
30 {
31     vector<Shape *> SomeShape;
32     SomeShape.push_back(new Apple());
33     SomeShape.push_back(new Pear());
34 
35     for(vector<Shape *>::iterator itr=SomeShape.begin(),end=SomeShape.end();itr!=end;++itr)
36     {
37         (*itr)->draw();
38     }
39 }

 Polymorphism,Virtual Functions and Dynamic Binding "under the hood"

1、The UML class diagram shows the inheritance hierarchy for our polymorphic employee payroll application.

 

2、Source Code

Employee.h
 1 // Employee.h
 2 // Employee abstract base class.
 3 #ifndef EMPLOYEE_H
 4 #define EMPLOYEE_H
 5 
 6 #include <string> // C++ standard string class
 7 using std::string;
 8 
 9 class Employee 
10 {
11 public:
12    Employee( const string &, const string &, const string & );
13 
14    void setFirstName( const string & ); // set first name
15    string getFirstName() const; // return first name
16 
17    void setLastName( const string & ); // set last name
18    string getLastName() const; // return last name
19 
20    void setSocialSecurityNumber( const string & ); // set SSN
21    string getSocialSecurityNumber() const; // return SSN
22 
23    // pure virtual function makes Employee abstract base class
24    virtual double earnings() const = 0; // pure virtual
25    virtual void print() const; // virtual
26 private:
27    string firstName;
28    string lastName;
29    string socialSecurityNumber;
30 }; // end class Employee
31 
32 #endif // EMPLOYEE_H
Employee.cpp
 1 //Employee.cpp
 2 // Abstract-base-class Employee member-function definitions.
 3 // Note: No definitions are given for pure virtual functions.
 4 #include <iostream>
 5 using std::cout;
 6 
 7 #include "Employee.h" // Employee class definition
 8 
 9 // constructor
10 Employee::Employee( const string &first, const string &last,
11    const string &ssn )
12    : firstName( first ), lastName( last ), socialSecurityNumber( ssn )
13 {
14    // empty body 
15 } // end Employee constructor
16 
17 // set first name
18 void Employee::setFirstName( const string &first ) 
19 { 
20    firstName = first;  
21 } // end function setFirstName
22 
23 // return first name
24 string Employee::getFirstName() const 
25 { 
26    return firstName;  
27 } // end function getFirstName
28 
29 // set last name
30 void Employee::setLastName( const string &last )
31 {
32    lastName = last;   
33 } // end function setLastName
34 
35 // return last name
36 string Employee::getLastName() const
37 {
38    return lastName;   
39 } // end function getLastName
40 
41 // set social security number
42 void Employee::setSocialSecurityNumber( const string &ssn )
43 {
44    socialSecurityNumber = ssn; // should validate
45 } // end function setSocialSecurityNumber
46 
47 // return social security number
48 string Employee::getSocialSecurityNumber() const
49 {
50    return socialSecurityNumber;   
51 } // end function getSocialSecurityNumber
52 
53 // print Employee's information (virtual, but not pure virtual)
54 void Employee::print() const
55 { 
56    cout << getFirstName() << ' ' << getLastName() 
57       << "\nsocial security number: " << getSocialSecurityNumber(); 
58 } // end function print
SalariedEmployee.h
 1 //SalariedEmployee.h
 2 // SalariedEmployee class derived from Employee.
 3 #ifndef SALARIED_H
 4 #define SALARIED_H
 5 
 6 #include "Employee.h" // Employee class definition
 7 
 8 class SalariedEmployee : public Employee 
 9 {
10 public:
11    SalariedEmployee( const string &, const string &, 
12       const string &, double = 0.0 );
13 
14    void setWeeklySalary( double ); // set weekly salary
15    double getWeeklySalary() const; // return weekly salary
16 
17    // keyword virtual signals intent to override
18    virtual double earnings() const; // calculate earnings
19    virtual void print() const; // print SalariedEmployee object
20 private:
21    double weeklySalary; // salary per week
22 }; // end class SalariedEmployee
23 
24 #endif // SALARIED_H
SalariedEmployee.cpp
 1 //SalariedEmployee.cpp
 2 // SalariedEmployee class member-function definitions.
 3 #include <iostream>
 4 using std::cout;
 5 
 6 #include "SalariedEmployee.h" // SalariedEmployee class definition
 7 
 8 // constructor 
 9 SalariedEmployee::SalariedEmployee( const string &first, 
10    const string &last, const string &ssn, double salary )
11    : Employee( first, last, ssn )
12 { 
13    setWeeklySalary( salary ); 
14 } // end SalariedEmployee constructor
15 
16 // set salary
17 void SalariedEmployee::setWeeklySalary( double salary )
18 { 
19    weeklySalary = ( salary < 0.0 ) ? 0.0 : salary; 
20 } // end function setWeeklySalary
21 
22 // return salary
23 double SalariedEmployee::getWeeklySalary() const
24 {
25    return weeklySalary;
26 } // end function getWeeklySalary
27 
28 // calculate earnings; 
29 // override pure virtual function earnings in Employee
30 double SalariedEmployee::earnings() const 
31 { 
32    return getWeeklySalary(); 
33 } // end function earnings
34 
35 // print SalariedEmployee's information 
36 void SalariedEmployee::print() const
37 {
38    cout << "salaried employee: ";
39    Employee::print(); // reuse abstract base-class print function
40    cout << "\nweekly salary: " << getWeeklySalary();
41 } // end function print
CommissionEmployee.h
 1 //CommissionEmployee.h
 2 // CommissionEmployee class derived from Employee.
 3 #ifndef COMMISSION_H
 4 #define COMMISSION_H
 5 
 6 #include "Employee.h" // Employee class definition
 7 
 8 class CommissionEmployee : public Employee 
 9 {
10 public:
11    CommissionEmployee( const string &, const string &,
12       const string &, double = 0.0, double = 0.0 );
13 
14    void setCommissionRate( double ); // set commission rate
15    double getCommissionRate() const; // return commission rate
16 
17    void setGrossSales( double ); // set gross sales amount
18    double getGrossSales() const; // return gross sales amount
19 
20    // keyword virtual signals intent to override
21    virtual double earnings() const; // calculate earnings
22    virtual void print() const; // print CommissionEmployee object
23 private:
24    double grossSales; // gross weekly sales
25    double commissionRate; // commission percentage
26 }; // end class CommissionEmployee
27 
28 #endif // COMMISSION_H
CommissionEmployee.cpp
 1 // CommissionEmployee.cpp
 2 // CommissionEmployee class member-function definitions.
 3 #include <iostream>
 4 using std::cout;
 5 
 6 #include "CommissionEmployee.h" // CommissionEmployee class definition
 7 
 8 // constructor 
 9 CommissionEmployee::CommissionEmployee( const string &first, 
10    const string &last, const string &ssn, double sales, double rate )
11    : Employee( first, last, ssn )  
12 {
13    setGrossSales( sales );
14    setCommissionRate( rate );
15 } // end CommissionEmployee constructor
16 
17 // set commission rate
18 void CommissionEmployee::setCommissionRate( double rate )
19 { 
20     commissionRate = ( ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0 );
21 } // end function setCommissionRate
22 
23 // return commission rate
24 double CommissionEmployee::getCommissionRate() const
25 {
26     return commissionRate;
27 } // end function getCommissionRate
28 
29 // set gross sales amount
30 void CommissionEmployee::setGrossSales( double sales ) 
31 { 
32    grossSales = ( ( sales < 0.0 ) ? 0.0 : sales ); 
33 } // end function setGrossSales
34 
35 // return gross sales amount
36 double CommissionEmployee::getGrossSales() const
37 {
38     return grossSales;
39 } // end function getGrossSales
40 
41 // calculate earnings;
42 // override pure virtual function earnings in Employee
43 double CommissionEmployee::earnings() const
44 { 
45    return getCommissionRate() * getGrossSales(); 
46 } // end function earnings
47 
48 // print CommissionEmployee's information 
49 void CommissionEmployee::print() const
50 {
51    cout << "commission employee: ";
52    Employee::print(); // code reuse
53    cout << "\ngross sales: " << getGrossSales() 
54       << "; commission rate: " << getCommissionRate();
55 } // end function print
BasePlusCommissionEmployee.h
 1 // BasePlusCommissionEmployee.h
 2 // BasePlusCommissionEmployee class derived from Employee.
 3 #ifndef BASEPLUS_H
 4 #define BASEPLUS_H
 5 
 6 #include "CommissionEmployee.h" // CommissionEmployee class definition
 7 
 8 class BasePlusCommissionEmployee : public CommissionEmployee 
 9 {
10 public:
11    BasePlusCommissionEmployee( const string &, const string &,
12       const string &, double = 0.0, double = 0.0, double = 0.0 );
13 
14    void setBaseSalary( double ); // set base salary
15    double getBaseSalary() const; // return base salary
16 
17    // keyword virtual signals intent to override
18    virtual double earnings() const; // calculate earnings
19    virtual void print() const; // print BasePlusCommissionEmployee object
20 private:
21    double baseSalary; // base salary per week
22 }; // end class BasePlusCommissionEmployee
23 
24 #endif // BASEPLUS_H
BasePlusCommissionEmployee.cpp
 1 //  BasePlusCommissionEmployee.cpp
 2 // BasePlusCommissionEmployee member-function definitions.
 3 #include <iostream>
 4 using std::cout;
 5 
 6 // BasePlusCommissionEmployee class definition
 7 #include "BasePlusCommissionEmployee.h"
 8 
 9 // constructor 
10 BasePlusCommissionEmployee::BasePlusCommissionEmployee( 
11    const string &first, const string &last, const string &ssn, 
12    double sales, double rate, double salary )
13    : CommissionEmployee( first, last, ssn, sales, rate )  
14 {
15    setBaseSalary( salary ); // validate and store base salary
16 } // end BasePlusCommissionEmployee constructor
17 
18 // set base salary
19 void BasePlusCommissionEmployee::setBaseSalary( double salary )
20 { 
21    baseSalary = ( ( salary < 0.0 ) ? 0.0 : salary ); 
22 } // end function setBaseSalary
23 
24 // return base salary
25 double BasePlusCommissionEmployee::getBaseSalary() const
26 { 
27     return baseSalary; 
28 } // end function getBaseSalary
29 
30 // calculate earnings;
31 // override pure virtual function earnings in Employee
32 double BasePlusCommissionEmployee::earnings() const
33 { 
34     return getBaseSalary() + CommissionEmployee::earnings(); 
35 } // end function earnings
36 
37 // print BasePlusCommissionEmployee's information 
38 void BasePlusCommissionEmployee::print() const
39 {
40    cout << "base-salaried ";
41    CommissionEmployee::print(); // code reuse
42    cout << "; base salary: " << getBaseSalary();
43 } // end function print
main.cpp
 1 //main.cpp
 2 // Processing Employee derived-class objects individually 
 3 // and polymorphically using dynamic binding.
 4 #include <iostream>
 5 using std::cout;
 6 using std::endl;
 7 using std::fixed;
 8 
 9 #include <iomanip>
10 using std::setprecision;
11   
12 #include <vector>
13 using std::vector;
14 
15 // include definitions of classes in Employee hierarchy
16 #include "Employee.h"
17 #include "SalariedEmployee.h" 
18 #include "CommissionEmployee.h"  
19 #include "BasePlusCommissionEmployee.h" 
20 
21 void virtualViaPointer( const Employee * const ); // prototype
22 void virtualViaReference( const Employee & ); // prototype
23 
24 int main()
25 {
26    // set floating-point output formatting
27    cout << fixed << setprecision( 2 );
28 
29    // create derived-class objects
30    SalariedEmployee salariedEmployee( 
31       "John", "Smith", "111-11-1111", 800 );
32    CommissionEmployee commissionEmployee( 
33       "Sue", "Jones", "333-33-3333", 10000, .06 );
34    BasePlusCommissionEmployee basePlusCommissionEmployee( 
35       "Bob", "Lewis", "444-44-4444", 5000, .04, 300 );
36    
37    cout << "Employees processed individually using static binding:\n\n";
38 
39    // output each Employee's information and earnings using static binding
40    salariedEmployee.print();
41    cout << "\nearned $" << salariedEmployee.earnings() << "\n\n";
42    hourlyEmployee.print(); 
43    cout << "\nearned $" << hourlyEmployee.earnings() << "\n\n";
44    commissionEmployee.print();
45    cout << "\nearned $" << commissionEmployee.earnings() << "\n\n";
46    basePlusCommissionEmployee.print();
47    cout << "\nearned $" << basePlusCommissionEmployee.earnings() 
48       << "\n\n";
49 
50    // create vector of four base-class pointers
51    vector < Employee * > employees( 3 );
52 
53    // initialize vector with Employees
54    employees[ 0 ] = &salariedEmployee;
55    employees[ 1 ] = &commissionEmployee;
56    employees[ 2 ] = &basePlusCommissionEmployee;
57 
58    cout << "Employees processed polymorphically via dynamic binding:\n\n";
59 
60    // call virtualViaPointer to print each Employee's information
61    // and earnings using dynamic binding
62    cout << "Virtual function calls made off base-class pointers:\n\n";
63 
64    for ( size_t i = 0; i < employees.size(); i++ )
65       virtualViaPointer( employees[ i ] );
66 
67    // call virtualViaReference to print each Employee's information 
68    // and earnings using dynamic binding
69    cout << "Virtual function calls made off base-class references:\n\n";
70 
71    for ( size_t i = 0; i < employees.size(); i++ )    
72       virtualViaReference( *employees[ i ] ); // note dereferencing
73 
74    return 0;
75 } // end main
76 
77 // call Employee virtual functions print and earnings off a 
78 // base-class pointer using dynamic binding
79 void virtualViaPointer( const Employee * const baseClassPtr )
80 {
81    baseClassPtr->print();
82    cout << "\nearned $" << baseClassPtr->earnings() << "\n\n";
83 } // end function virtualViaPointer
84 
85 // call Employee virtual functions print and earnings off a 
86 // base-class reference using dynamic binding
87 void virtualViaReference( const Employee &baseClassRef )
88 {
89    baseClassRef.print();
90    cout << "\nearned $" << baseClassRef.earnings() << "\n\n";
91 } // end function virtualViaReference

 3、Output:

 

4、Under the Hood

When C++ compiles a class that has one or more virtual functions, it builds a virtual function table (vtable) for that class. An executing program uses the vtable to select the proper function implementation each time a virtual function of that class is called.Whenever an object of a class with one or more virtual functions is instantiated, the compiler attaches to the object a pointer to the vtable for that class.The third level of pointers simply contains the handles to the objects that receive the virtual function calls

When the compiler compiles this statement, it determines that the call is indeed being made via a base-class pointer and that print is a virtual function.The compiler determines that print is the second entry in each of the vtables. To locate this entry, the compiler notes that it will need to skip the first entry. Thus, the compiler compiles an offset or displacement into the table of machine-language object-code pointers to find the code that will execute the virtual function call. The size in bytes of the offset depends on the number of bytes used to represent a pointer on an individual platform.

The compiler generates code that performs the following operations

1). Select the ith entry of employees (in this case, the address of object commissionEmployee), and pass it as an argument to function virtualViaPointer. This sets parameter baseClassPtr to point to commissionEmployee.

2). Dereference that pointer to get to the commissionEmployee object—which, as you recall, begins with a pointer to the CommissionEmployee vtable.

3). Dereference commissionEmployee’s vtable pointer to get to the CommissionEmployee vtable

4). Skip the offset of four bytes to select the print function pointer.

5). Dereference the print function pointer to form the “name” of the actual function to execute, and use the function call operator () to execute the appropriate print function, which in this case prints the employee’s type, name, social security number, gross sales and commission rate.

Fig. 13.18’s data structures may appear to be complex, but this complexity is managed by the compiler and hidden from you, making polymorphic programming straightforward.The pointer dereferencing operations and memory accesses that occur on every virtual function call require some additional execution time. The vtables and the vtable pointers added to the objects require some additional memory.

 


Operator Overloading

 1 #include <stdexcept>
 2 #include <iostream>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     string str1("better ");
10     string str2("late ");
11     string str3="than ";
12     string str4;
13     string str5;
14 
15     //copy constructor
16     //This results in a call to class string's copy constructor.
17     string str6(str5);
18 
19     //support logic operators:== != > < >= <=
20     if(str1==str2)
21     {
22         cout<<"str1==str2"<<endl;
23     }
24     else if(str1>str2)
25     {
26         cout<<"str1>str2"<<endl;
27     }
28     else if(str1<str2)
29     {
30         cout<<"str1<str2"<<endl;
31     }
32     //support assignment operator:=
33     str4=str1;
34     //self-assignment.
35     str6=str6;
36     //support concatenate operator:+.
37     str5 +=str1+str2+str3+"never";
38     //subscript operator:[]
39     //class string's [] operator does not perform any bounds checking.
40     str5[0]='B';
41     str5[7]='L';
42     str5[12]='T';
43     str5[17]='N';
44     cout<<str5<<endl;
45 
46     //function "substr"
47     cout<<str5.substr(0,20)<<endl;
48     cout<<str5.substr(0)<<endl;
49     //function "empty"
50     str5.empty()?cout<<"empty"<<endl:cout<<"not empty"<<endl;
51     //function "at"
52     //function 'at' throws an exception if its argument is an invalid subcript.
53     try
54     {
55         str5.at(40)='A';
56     }
57     catch(out_of_range &e)
58     {
59         cout<<e.what()<<endl;
60     }
61 
62 }

Fundamentals Of Operator Overloadding

Operator overloading is not automatic—you must write operator-overloading functions to perform the desired operations. An operator is overloaded by writing a nonstatic member function definition or non-member function definition.When operators are overloaded as member functions, they must be non-static,because they must be called on an object of that class or operate on that object.To use an operator on an object of a class, the operator must be overloaded for that class—with three exceptions:"=" 、"&" 、"," these three operators can be used with every object without overloadding priviously.

As you prepare to overload operator with your own classes, there are several rules and restrictions you should keep in mind:

• The precedence of an operator cannot be changed by overloading. However, parentheses can be used to force the order of        evaluation of overloaded operators in an expression.
• The associativity of an operator cannot be changed by overloading—if an operator normally associates from left to right, then      so do all of its overloaded versions.
• You cannot change the “arity” of an operator (that is, the number of operands an operator takes)—overloaded nary perators   remain unary operators; overloaded binary operators remain binary operators. Operators &, *, + and - all have both unary and binary versions; these unary and binary versions can be separately overloaded.
• You cannot create new operators; only existing operators can be overloaded.
• The meaning of how an operator works on values of fundamental types cannot be changed by operator overloading. For example, you cannot make the + operator ubtract two ints. Operator overloading works only with objects of user-defined
types or with a mixture of an object of a user-defined type and an object of a fundamental type.
• Related operators, like + and +=, must be overloaded separately.
• When overloading (), [], -> or any of the assignment operators, the operator overloading function must be declared as a class member. For all other overloadable operators, the operator overloading functions can be member functions or
non-member functions.

Overload Binary Operator

1、overloadded as non-static member function

A binary operator can be overloaded as a non-static member function with one parameter or as a non-member function with two parameters . A non-member operator function is often declared as friend of a class for performance reasons.

They’re non-member functions because the object of class PhoneNumber must be the operator’s right operand

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <string>
 4 using namespace std;
 5 
 6 class PhoneNumber
 7 {
 8     //'operator<<' and 'operator>>' are declared friend if they meed to access non-public
 9     //class members directly for the performance reasons or because the class does not offer
10     //appropriate get functions.
11     friend ostream & operator<<(ostream & output,const PhoneNumber & phone);
12     friend istream & operator>>(istream & input,PhoneNumber & phone);
13 
14 private:
15     string areaCode;
16     string exchange;
17     string line;
18 };
19 
20 //'operator<<' and 'operator>>' are declared as non-member functions because
21 //the object of class PhoneNumber is wanted to be the operator's right operand.
22 ostream & operator<<(ostream & output,const PhoneNumber & phone);
23 istream & operator>>(istream & input,PhoneNumber & phone);
24 
25 ostream & operator<<(ostream & output,const PhoneNumber & phone)
26 {
27     output<<"("<<phone.areaCode<<")"<<" "<<phone.exchange<<"-"<<phone.line<<endl;
28     return output;
29 }
30 
31 istream & operator>>(istream &input,PhoneNumber & phone)
32 {
33     //parentheses space dash are skipped by input's member function 'ignore()'.
34     input.ignore();
35     //stream manipulator 'setw()' limits the number of characters read into each stream.
36     input>>setw(3)>>phone.areaCode;
37     input.ignore(2);
38     input>>setw(3)>>phone.exchange;
39     input.ignore(1);
40     input>>setw(4)>>phone.line;
41 
42     return input;
43 }
44 
45 int main()
46 {
47     cout<<"Please enter a phone number in the form:\'(020) 123-4567\'"<<endl;
48     PhoneNumber oPhone;
49     cin>>oPhone;
50     cout<<"output phone number:"<<oPhone;
51 }

Overloading Unary Operators

A unary operator for a class can be overloaded as a non-static member function with no arguments or as a non-member function with one argument that must be an object (or a reference to an object) of the class. Member functions that implement overloaded operators must be non-static so that they can access the non-static data in each object of the class.

  1 #ifndef DATE_H_INCLUDED
  2 #define DATE_H_INCLUDED
  3 #include <iostream>
  4 
  5 using namespace std;
  6 
  7 class Date
  8 {
  9     friend ostream& operator<<(ostream & output,const Date & date);
 10 public:
 11     //Constructors and Destructor
 12     Date(int=1,int=1,int=2000);
 13     ~Date();
 14 
 15     //Interface
 16     bool setDate(int m,int d,int y);
 17     Date& operator++();//prefix increment operator
 18     //Note that this function return Date object by value
 19     Date operator++(int);//postfix increment operator
 20     Date& operator+=(int);
 21 
 22 private:
 23     //Utility functions
 24     static bool isLeapYear(int y);
 25     bool isEndOfMonth(int dd);
 26     void increment();
 27 
 28     //Private data.
 29     int _year;
 30     int _month;
 31     int _day;
 32     static const string _year2String[13];
 33     static const int _monthDay[13];
 34 };
 35 
 36 #endif // DATE_H_INCLUDED
 37 //-------------------------------------------------------------------------------------------
 38 #include <iostream>
 39 #include <string>
 40 #include <stdexcept>
 41 #include "Date.h"
 42 
 43 using namespace std;
 44 
 45 ostream& operator<<(ostream & output,const Date & date)
 46 {
 47     cout<<date._year2String[date._month]<<" "<<date._day<<" ,"<<date._year;
 48     return output;
 49 }
 50 
 51 Date::Date(int m,int d,int y)
 52 {
 53     setDate(m,d,y);
 54 }
 55 
 56 Date::~Date()
 57 {
 58 
 59 }
 60 
 61 bool Date::setDate(int m,int d,int y)
 62 {
 63     if(0<m&&13>m)
 64         _month=m;
 65     else
 66     {
 67         throw invalid_argument("month out of range.");
 68     }
 69 
 70     if( (d>0&&d<=_monthDay[m]) || (isLeapYear(y)&&m==2&&d>0&&d<=29) )
 71     {
 72         _day=d;
 73     }
 74     else
 75     {
 76         throw invalid_argument("Day out of range.");
 77     }
 78 
 79     if(y>0)
 80     {
 81         _year=y;
 82     }
 83     else
 84     {
 85         throw invalid_argument("invalid year.");
 86     }
 87 
 88     return true;
 89 }
 90 
 91 Date& Date::operator++()
 92 {
 93     increment();
 94     return *this;
 95 }
 96 
 97 //Note that the dummy integer parameter does not has a parameter name.
 98 Date Date::operator++(int)
 99 {
100     //must occure before increment() called.
101     //hold current state of object.
102     Date temp=*this;
103     increment();
104     //return a temporary object the contains the original value of the object
105     //before the increment occured.
106     return temp;
107 }
108 
109 Date& Date::operator+=(int nDays)
110 {
111     for(int i=0;i<nDays;++i)
112     {
113         increment();
114     }
115 
116     return *this;
117 }
118 
119 bool Date::isLeapYear(int y)
120 {
121     if((y%100!=0)&&(y%4==0) || (y%400==0) )
122         return true;
123     else
124         return false;
125 }
126 
127 bool Date::isEndOfMonth(int dd)
128 {
129     if(_month==2&&isLeapYear(_year))
130         return dd==29;
131     else
132         return dd==_monthDay[_month];
133 }
134 
135 void Date::increment()
136 {
137     if(!isEndOfMonth(_day))
138     {
139         ++_day;
140     }
141     else
142     {
143         if(_month<12)
144         {
145             ++_month;
146             _day=1;
147         }
148         else
149         {
150             ++_year;
151             _month=1;
152             _day=1;
153         }
154     }
155 }
156 
157 const int Date::_monthDay[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
158 const string Date::_year2String[13]={"","January","February","March","April","May","June",
159             "July","August","September","October","November","December"};
160 
161 //------------------------------------------------------------------------------------------------------
162 #include <iostream>
163 #include "Date.h"
164 
165 using namespace std;
166 
167 int main()
168 {
169     Date d1(1,1,1999);
170     Date d2(10,31,2013);
171 
172     d1.setDate(1,1,2000);
173     cout<<"  d1:"<<d1<<endl;
174     cout<<"++d1:"<<++d1<<endl;
175     cout<<"  d1:"<<d1<<endl;
176 
177     cout<<"\n\nd1  :"<<d1<<endl;
178     //When the complier sees the postincrementing expression d1++,it generates the
179     //member-function call d1.operator++(0);
180     cout<<"d1++:"<<d1++<<endl;
181     cout<<"d1  :"<<d1<<endl;
182 
183     d1++.setDate(1,1,1990);
184     cout<<d1<<endl;
185 
186     Date * poDate=new Date;
187     cout<<"\n\n"<<*poDate;
188     Date * poDate_2=new Date();
189     cout<<"\n\n"<<*poDate_2;
190 
191 
192 }

Array Class

 In this example, we create a powerful Array class that performs range checking to ensure that subscripts remain within the bounds of the Array. The class allows one array object to be assigned to another with the assignment operator. Array objects know their size, so the size does not need to be passed separately to functions that receive Array parameters. Entire Arrays can be input or output with the stream extraction and stream insertion operators, respectively. You can compare Arrays with the equality operators == and !=.

//main.cpp
//--------------------------------------------------------------------------------
#include <iostream>
#include "Array.h"

using namespace std;

void outputArray(const Array &);

int main()
{
    Array arrayOne(12);
    //test constructor with default argument.
    Array arrayTwo;
    //test overloadded operator <<
    cout<<arrayOne<<endl;
    cout<<arrayTwo<<endl;
    //test getSize() function
    cout<<"arrayTwo's size is:"<<arrayTwo.getSize()<<endl;

    //test >>
    Array arrayThird(5);
    Array arrayFourth(11);
    cout<<"Enter 16 integers:"<<endl;
    cin>>arrayThird>>arrayFourth;
    cout<<arrayThird<<arrayFourth<<endl;

    //test copy constructor
    Array arrayFifth(arrayOne);
    cout<<arrayFifth<<endl;

    //test overloadded operator []
    Array array(6);
    for(int i=0;i<array.getSize();++i)
    {
        array[i]=i;
    }
    cout<<array<<endl;
    //test overloadded operator =
    Array array_1(8);
    array_1=array;
    array=array;
    cout<<array_1<<endl;

    //test overloadded operator == !=
    Array array_2(7);
    array_2==array?cout<<"array_2==array"<<endl:cout<<"array_2!=array"<<endl;
    array_2!=array?cout<<"array_2!=array"<<endl:cout<<"array_2==array"<<endl;
    array_1==array?cout<<"array_1==array"<<endl:cout<<"array_1!=array"<<endl;

    const Array array_const(6);
    for(int i=0;i<array_const.getSize();++i)
    {
        cout<<"array_const["<<i<<"]="<<array_const[i]<<endl;
    }

    Array myArray(7);
    outputArray(myArray);
    outputArray(3);
}


//Array.h
//--------------------------------------------------------------------------------

#ifndef __ARRAY_H__
#define __ARRAY_H__

#include <iostream>
using namespace std;

class Array
{
    friend ostream& operator<<(ostream&,const Array&);
    friend istream& operator>>(istream&,Array&);
public:
    Array(int=10);
    Array(const Array&);//copy constructor.
    ~Array();

    int getSize() const;

    //overload operators
    const Array& operator=(const Array&);
    bool operator==(const Array&) const;
    bool operator!=(const Array&) const;
    //subscript for non-const objcet returns lvalue.
    int& operator[](int);
    //subscript for const objcet returns rvalue.
    int operator[](int) const;
private:
    int _size;
    int * _pInt;
};

#endif // __ARRAY_H__

//Array.cpp
//--------------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <string.h>
#include "Array.h"

using namespace std;

ostream& operator<<(ostream& output,const Array& array)
{
    output<<"Array Int["<<array.getSize()<<"]:\n";
    for(int i=0;i<array.getSize();++i)
    {
        output<<array._pInt[i]<<"\t";
        if((i+1)%8==0 )
        {
            output<<endl;
        }
    }
    //output two array continously without this statment will get and runtime error???
    output<<endl;

    return output;
}

istream& operator>>(istream& input,Array& array)
{
    for(int i=0;i<array.getSize();++i)
    {
        input>>array._pInt[i];
    }

    return input;
}

Array::Array(int arraySize)
{
    //parameter validation must needded.
    if(arraySize<0)
    {
        throw invalid_argument("array size must be positive.\n");
    }
    else
    {
        _size=arraySize;
        _pInt=new int[_size];
        //need to initialize the new created array.
        //why this function cannot set every element of the array to 0?????
        //but the for-loop done.
        //memset(_pInt,'\0',_size);
        for(int i=0;i<_size;++i)
        {
            _pInt[i]=0;
        }
    }
}

//copy constructor.
//memberwise assignment is dangerous for classed with pointer members.
//so we need to wirte a copy constructor.
Array::Array(const Array& array):_size(array._size)
{
    _pInt=new int[_size];
    for(int i=0;i<_size;++i)
    {
        _pInt[i]=array._pInt[i];
    }
}

Array::~Array()
{
    //release pointer-base array space
    delete [] _pInt;
}

int Array::getSize() const
{
    return _size;
}

//const return avoids (a1=a2)=a3
//avoids self-assigment,note that the size of the array may be different.
const Array& Array::operator=(const Array& array)
{
    if(&array!=this)
    {
        if(_size!=array._size)
        {
            delete [] _pInt;
            _size=array._size;
        }

        _pInt=new int[_size];
        for(int i=0;i<_size;++i)
        {
            _pInt[i]=array._pInt[i];
        }
    }

    return *this;//enables x=y=z for example.
}

//return true if all the private data of class array is the same.
bool Array::operator==(const Array& array) const
{
    if(_size!=array._size)
        return false;

    for(int i=0;i<_size;++i)
    {
        if(_pInt[i]!=array._pInt[i])
            return false;
    }

    return true;
}//end of function operator==()

bool Array::operator!=(const Array& array) const
{
    return !(*this==array);//invoke Array::operator==
}

//subscript for non-const objcet returns lvalue.
int& Array::operator[](int n)
{
    if(n<0||n>_size-1)
        throw invalid_argument("subscript out of range.");
    return _pInt[n];//reference return;
}

//subscript for const objcet returns rvalue.
int Array::operator[](int n) const
{
    if(n<0||n>=_size)
        throw invalid_argument("subscript out of range.");

    return _pInt[n];//copy return;
}

Converting between Types

The compiler knows how to perform certain conversions among fundamental types. You can use cast operators to force conversions among fundamental types.But what about user-defined types? The compiler cannot know in advance how to convert among user-defined types, and between user-defined types and fundamental types, so you must specify how to do this. Such conversions can be performed with conversion
constructors—single-argument constructors that turn objects of other types (including fundamental types) into objects of a particular class.A conversion operator (also called a cast operator) can be used to convert an object of one class into an object of another class or into an object of a fundamental type. Such a
conversion operator must be a non-static member function.

 1 //declares an overloaded cast operator function for converting an object of user-defined type
 2 //A into a temporary char * object.
 3 //An overloaded cast operator function does not specify a return type—the return type is the type 
 4 //to which the object is being converted.
 5 // If s is a class object, when the compiler sees the expression static_cast< char * >( s ), the compiler
 6 //generates the call s.operator char *()
 7 A::operator char *() const;
 8 //declare overloaded cast operator functions that can convert an object of user-defined type A
 9 //into an object of user-defined type OtherClass.
10 A::operator OtherClass() const;

One of the nice features of cast operators and conversion constructors is that, when necessary, the compiler can call these functions implicitly to create temporary objects. For example, if an object s of a user-defined String class appears in a program at a location where an ordinary char * is expected, such as  cout << s;the compiler can call the overloaded cast-operator function operator char * to convert the object into a char * and use the resulting char * in the expression. With this cast operator provided for a String class, the stream insertion operator does not have to be overloaded to output a String using cout.

 explicit Constructors

Any single-argument constructor—except a copy constructor—can be used by the compiler to perform an implicit conversion. The constructor’s argument is converted to an object of the class in which theconstructor is defined. The conversion is automatic and you need not use a cast operator. In some situations, implicit conversions are undesirable or errorprone.

 1 #include <iostream>
 2 #include "Array.h"
 3 
 4 using namespace std;
 5 
 6 void outputArray(const Array &);
 7 
 8 int main()
 9 {
10     Array myArray(7);
11     outputArray(myArray);
12     outputArray(3);
13 }
14 
15 void outputArray(const Array &array_1)
16 {
17     cout<<array_1<<endl;
18 }

Line 12 calls function outputArray with the int value 3 as an argument. However, this program does not contain a function called outputArray that takes an int argument.So, the compiler determines whether class Array provides a conversion constructor that can convert an int into an Array. Since the Array constructor receives one int argument, the compiler assumes that the constructor is a conversion constructor that can be used to convert the argument 3 into a temporary Array object containing three elements. Then, the
compiler passes the temporary Array object to function outputArray to output the Array’s contents. Thus, even though we do not explicitly provide an outputArray function that receives an int argument, the compiler is able to compile line 12.

C++ provides the keyword explicit to suppress implicit conversions via conversion constructors when such conversions should not be allowed. A constructor that’s declared explicit cannot be used in an implicit conversion.So,what we only have to do is adding  a additional keyword explicit  into the constructor Array(int=10); defined in  in Array.h.

explicit Array( int = 10 ); // default constructor
1     Array myArray(7);
2     outputArray(myArray);
3     //this time ,this statement gets an error.
4     outputArray(3);
5     //demonstrates how the explicit constructor can be used to create a temporary
6     // Array of 3 elements and pass it to function outputArray.
7     outputArray(Array(3));

 


Templates

Introduction

Function templates and class templates enable you to specify, with a single code segment, an entire range of related (overloaded) functions—called function-template specializations—or an entire range of related classes—called class-template specializations.This technique is called generic programming.Note the distinction between templates and template specializations: Function templates and class templates are like stencils out of which we trace shapes; function-template specializations and class-template specializations are like the separate tracings that all have the same shape, but could, for example, be drawn in different colors.templates are often defined in headers, which are then #included in the appropriate client source-code files. For class templates, this means that the member functions are also defined in the header.

Function Templates

Initially, you write a single function-template definition. Based on the argument types provided explicitly or inferred from calls to this function, the compiler generates separate source-code functions (i.e., function-template specializations) to handle each function call appropriately.

 1 // Using template functions.
 2 #include <iostream>
 3 using std::cout;
 4 using std::endl;
 5 
 6 // function template printArray definition
 7 template< typename T >
 8 void printArray( const T *array, int count )
 9 {
10    for ( int i = 0; i < count; i++ )
11       cout << array[ i ] << " ";
12 
13    cout << endl;
14 } // end function template printArray
15 
16 int main()
17 {
18    const int aCount = 5; // size of array a
19    const int bCount = 7; // size of array b
20    const int cCount = 6; // size of array c
21 
22    int a[ aCount ] = { 1, 2, 3, 4, 5 };
23    double b[ bCount ] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
24    char c[ cCount ] = "HELLO"; // 6th position for null
25 
26    cout << "Array a contains:" << endl;
27 
28    // call integer function-template specialization
29    printArray( a, aCount );  
30 
31    cout << "Array b contains:" << endl;
32 
33    // call double function-template specialization
34    printArray( b, bCount );  
35 
36    cout << "Array c contains:" << endl;
37 
38    // call character function-template specialization
39    printArray( c, cCount );  
40    return 0;
41 } // end main

When the compiler detects a printArray function invocation in the client program (e.g., lines 29 and 34), the compiler uses its overload resolution capabilities to find a definition of function printArray that best matches the function call. In this case, the only printArray function with the appropriate number of parameters is the printArray function template (lines 7–14).Consider the function call at line 29. The compiler compares the type of printArray’s first argument (int * at line 29) to the printArray function template’s first parameter (const T * const at line 8) and deduces that replacing the type parameter T with int would make the argument consistent with the parameter. Then, the compiler substitutes int for T throughout the template definition and compiles a printArray specialization that can display an array of int values.In this example, the template mechanism saves you from having to write two separate overloaded functions with prototypes

void printArray( const int * const, int );
void printArray( const double * const, int );
void printArray( const char * const, int );

Although templates offer software-reusability benefits, remember that multiple functiontemplate specializations and class-template specializations are instantiated in a program (at compile time), despite the fact that the templates are written only once. These copies can consume considerable memory. This is not normally an issue, though, because the code generated by the template is the same size as the code you’d have written to produce the separate overloaded functions.

 Function Templates Can Be Overloadded

A function template may be overloaded in several ways. We can provide other function templates that specify the same function name but different function parameters.A function template also can be overloaded by providing nontemplate functions with the same function name but different function arguments.

The compiler performs a matching process to determine what function to call when a function is invoked. First, the compiler tries to find and use a precise match in which the function names and argument types are consistent with those of the function call. If this fails, the compiler determines whether a function template is available that can be used to generate a function-template specialization with a precise match of function name and argument types that are consistent with those of the function call. If such a template is
found, the compiler generates and uses the appropriate function-template specialization. If not, the compiler generates an error message. Also, if there are multiple matches for the function call, the compiler attempts to determine the best match. If there is more than one best match, the call is ambiguous and the compiler generates an error message.

Class Templates

 

 

 


Conventions

1、I have also put underscores before each private element of the class to make it easier to tell what is private, but it is not a requirement of C++. It looks a bit ugly at first, but I find it makes a big difference when you're reading the code! If you follow this convention, just make sure that you do not use a capital letter after the underscore; this prefix may cause conflicts with some compilers. As long as you stick with a lowercase letter after the underscore when declaring private fields or methods, you’ll be fine.

In my own code, I always start with a public section, followed by a private section. This emphasizes that the public section is meant for users of the class (other programmers) because it is the first thing that a user of the class will see.

 1 class ChessBoard
 2 { 
 3 public:
 4     ChessPiece getPiece (int x, int y); 
 5     PlayerColor getMove (); 
 6     void makeMove (int from_x, int from_y, int to_x, int to_y); 
 7 private:
 8     ChessPiece _board[ 8 ][ 8 ]; 
 9     PlayerColor _whose_move; 
10 };

 2、After deleting a pointer, it is a good idea to reset it to point to NULL again:

1 delete pInt;
2 pInt =NULL;

 3、Typical Class Design

Typical Class Design
 1 Typical Class Design
 2  //SysTest.h
 3  //-----------------------------------------------------------------
 4  #ifndef __SYS_TEST_H__
 5  #define __SYS_TEST_H__
 6  
 7  #define LOG(msg) std::cout<<__FILE__<<"-"<<__LINE__<<":"<<msg<<std::endl;
 8  
 9  class SysTest
10  {
11  public:
12      SysTest();
13      ~SysTest();
14      static SysTest * instance();
15      bool connectIPC();
16  private:
17      static SysTest * poInstance;
18  };
19  
20  #endif
21  
22  //SysTest.cpp
23  //------------------------------------------------------------------------
24  #include "SysTest.h"
25  
26  SysTest * SysTest::poInstance=0;
27  
28  SysTest * SysTest::instance()
29  {
30      if(0==poInstance)
31      {
32          poInstance = new SysTest();
33      }
34  
35      return poInstance;
36  }
37  
38  bool SysTest::connectIPC()
39  {
40  
41  }
42  
43  
44  //main.cpp
45  //-----------------------------------------------------------------
46  
47  #include "SysTest.h"
48  
49  int main()
50  {
51      if(!SysTest::instance()->connectIPC())
52          {
53          LOG("connect IPC failed");
54          return -1;
55      }
56      
57  }

 

posted on 2013-03-23 21:00  siszqsqx  阅读(1164)  评论(0编辑  收藏  举报

导航