zoukankan      html  css  js  c++  java
  • 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  }
  • 相关阅读:
    hdu 1213 (How Many Tables)(简单的并查集,纯模板)
    Android 开发 -------- 自己定义View 画 五子棋
    POJ 2472 106 miles to Chicago
    android application
    Effective C++:条款39:明智而审慎地使用private继承
    云计算统一办公运营平台服务能力设计方案
    LCA 近期公共祖先 小结
    MFC exe使用C++ dll中的std::string 崩溃
    函数调用堆栈图
    【cocos2d-js官方文档】二十、moduleConfig.json
  • 原文地址:https://www.cnblogs.com/hshuzhao/p/2976206.html
Copyright © 2011-2022 走看看