第 11 章 第一個 C++ 程式

本 章 主 要 內 容 如 下:

回第 10 章
至第 12 章
回 C 程式主目錄


第 11.1 節 第一個 C++ 程式

由 10.1 節的方法 2, 利用 stack 來解決標準括號式的問題,於檔案 stack.h 與 stack.c 已具有 C++ class 中資料封包的性質,以 class 的方式重新整 理 stack.h 與 stack.c 成為新的檔案 stack.cpp 其內容為

         #define  MAXSIZE  100
         class  CStack
         {   
         public:
             CStack( )  {  tos=0;  }
            ~CStack( )  {  }
             int  isEmpty( ) {  return tos == 0;  }
             int  isFull( )  {  return tos == MAXSIZE;  }
             void  push(char c) {  s[tos++]=c;  }
             char  pop( )  {  return s[--tos];  }
         private:
             char  s[MAXSIZE];
              int  tos;
         }

說明:

  1. 新的 stack.cpp 檔 (注意其副檔名已經改成為 .cpp,其發音為 C plus plus, 即 C++ ) 含一類別 (class) 的宣告,該 class 的名稱為 CStack。
  2. class CStack 含有二個 private 的 data members,即 s 與 tos。
  3. class CStack 含有四個 member functions,即 isEmpty()、 isFull()、 push() 及 pop()。
  4. class CStack 含有一個 建構函數 (constructor) CStack(), 該函數 如同第 10 章中的 initializeStack() 函數。
    任意一個 class 都有一個 預設 (default) 建構函數, 即使 不將它 標明出來, 它仍然 存在。 一個 class 可能 含有 一個 或 多個 建構函數。 如有多個函數 其名皆相同, 則稱之為 overloaded function, 將於 第 3 節討論。
  5. class CStack 含有一個 解構函數 (destructor) ~CStack()。 於 destructor 中 可用來 釋放 一些 動態記憶体 或處理 其他一些事。
    任意一個 class 都有一個 預設 (default) 解構函數, 一個 class 也可能 含有 一個 或 多個 解構函數。

將檔案 main.c 改為 main.cpp 其內容如下:

         #include  <stdio.h>
         #include  "stack.cpp"
         main( )
         {   CStack  stack;
             char  c;
             while ( ( c=getchar() ) != '\n' )
             {   if(c=='(')  stack.push(c);
                 eise if (c==')')
                 {  if (stack.isEmpty())
                    { printf("Eorror input!\n");return;}
                    else stack.pop();
                  }
                 else { printf("Eorror input!\n");return;}
             }
             if (stack.isEmpty()) printf("Correct input!\n");
             else printf("Eorror input!\n");
         }
說明:
  1. 於 main() 中我們宣告了一物件 stack 其類別為 CStack
  2. class 如同一 資料型態,並不佔有 記憶體 空間。一個 class 的變數 不稱為 變數 而稱為 物件,該物件如同 變數 一樣占有 記憶體空間。
  3. 對於物件 stack ,它含有兩個 private data members s 與 tos ,因其 屬性為 private 故無法直接引用 stack.s[] 及 stack.tos。我們必須經由該 class 的 member functions 來改變 這兩個變數的值。
  4. 於第 10 章 stack.c 的設計方式,如果我們想要有 第二個 相同的 stack ,那麼非 複製一份 stack.c 檔不可,且 函數名稱 也必須更改,當然 stack.h 也要有 新的一份。然而 對於 class 的 設計方式 就不用了。我們可以用 下列方式 即可得到 兩個 屬於同一個 class 的物件 S1 與 S2
             CStack S1,S2;
    
    那麼 S1 與 S2 分別有其變數 S 與 tos。當引用 member functions 如
             S1.push(c);   S2.push(c)
    
    物件 S1 與 S2 彼此都不互相影響。
  5. 以 class 來設計程式相當容易達到 code reusability 的要求,即將 stack.cpp 含進一檔案即可。然而, 欲達其 彈性的使用, class 尚有 其他 特性 可以 加以使用,將於 接下 幾章說明。不過 一般而言, stack.cpp 檔將會分 成兩個檔案, 一個是 stack.h 檔,另一個是 stack.cpp。

一般而言檔案 stack.h 的內容僅含 data members 及 member functions 的宣告,其內容 如下:

        #define  MAXSIZE  100
        class  CStack
        {   
	    public:
                     CStack( );
                    ~CStack( );
                int  isEmpty( );
                int  isFull( );
               void  push(char c);
               char  pop( );
            private:
               char  s[MAXSIZE];
                int  tos;
         }
檔案 stack.cpp 才將 member functions 的定義 (implmentation) 加進去。不過每個 member functions 都要加上 class specification CStack::, 該 檔案的 內容如下:
         #include  "stack.h"
         CStack::  CStack( ){  tos=0;  }
         CStack::  ~CStack( ){ }

         int   CStack::  isEmpty( ){ return tos==0; }
         int   CStack::  isFull( ){ return tos==MAXSIZE; }
         void  CStack::  push(char c){ s[tos++]=c; }
         char  CStack::  pop( ){ return s[--tos]; }   

當 class 的宣告, data members s 與 tos 之前的 private 去掉,那麼 data protection 就沒有了,其屬性變成 public, 資料的一致性也無法達成。 此時對於物件 stack 而言,即可直接引用 s 及 tos 如 stack.tos=1002; stack.s[1]=100;等。

一般而言, private 的 data members 及 member functions 都是放在 class 宣告的尾部。

回本章主目錄


第 11.2 節 new 與 delete operators 及 iostream.h 檔

陣列亦可以經由 動態( dynamic ) 方式取得, 於 C 程式語言 是以 malloc 函數 呼叫方式取得 動態記憶体, 於 C++ 程式語言 是以 new 來取得 動態記憶体。

於 C 程式語言 是以 free 方式來釋放 動態記憶体, 於 C++ 程式語言 是以 delete 方式來釋放 動態記憶体。

將上一個程式修改成下列的程式如下:

檔案 stack.h 的內容 如 例 1 所示。

例 1 :

        #define MAXSIZE 100
        class  CStack
        {   
	    public:
                     CStack( );
                    ~CStack( );
                int  isEmpty( );
                int  isFull( );
               void  push(char c);
               char  pop( );
            private:
               char  *s;
                int  tos;
         }

說明:

  1. class CStack 含有二個 private 的 data members, 即 s 與 tos。
  2. class CStack 含有四個 member functions,即 isEmpty()、 isFull()、 push() 及 pop()。
  3. class CStack 含有一個 constructor CStack()。
  4. class CStack 含有一個 destructor ~CStack()。 於 destructor 中 可用來釋放 一些 動態記憶体。

檔案 stack.cpp 的內容 如下:

      #include  "stack.h"
      CStack::  CStack( ){  tos=0;  s = new char[MAXSIZE]; }
      CStack::  ~CStack( ){ delete [] s; }

      int   CStack::  isEmpty( ){ return tos==0; }
      int   CStack::  isFull( ){ return tos==MAXSIZE; }
      void  CStack::  push(char c){ s[tos++]=c; }
      char  CStack::  pop( ){ return s[--tos]; }   

說明:

  1. new 的功能 如同 C 之 malloc 用來取得 動態記憶体, 於上例 是用以處理 陣列的取得。
  2. delete 的功能 如同 C 之 free 用來釋放 動態記憶体, 於上例 是用以釋放 陣列所佔有的記憶体。
  3. delete s 僅釋放 s 所指的 一個 char, 無法將整個陣列釋放, 欲釋放整個陣列, 則須 標示 陣列符號 [], 即 delete [] s。

檔案 main.cpp 其內容如下:

         #include  <iostream.h>  // 已經將 stdio.h 換成 iostream.h
         #include  "stack.h"
         main( )
         {   CStack  stack;
             char  c;
             while ((cin >> c)!='\n')
             {   if(c=='(')  stack.push(c);
                 else if (c==')')
                 {  if (stack.isEmpty())
                    { cout << "Error input!\n";
                      return;
                    }
                    else stack.pop();
                  }
                 else { cout << "Error input!\n"; return;}
             }
             if (stack.isEmpty()) cout << "Correct input!\n";
             else cout << "Error input!\n";
         }

說明:

  1. 指令 cin 為輸入指令,定義於 iostream.h
    其格式為 cin >> 變數 >> 字串;
  2. 指令 cout 為輸出指令,定義於 iostream.h
    其格式為 cout << 變數 << 字串;
    欲跳行,可以用 cout << endl; 來替代 cout <<"\n";。 其中 endl 表 end of line。

回本章主目錄


第 11.3 節 overloaded functions

C++ 程式語言容許同一個函數名稱有不同的用法, 事實上 C 程式語言亦有 類似情形, 如 2 + 3 2.0 + 3.0 , 對於加法 運算可以 用在 集合 int x int 與 集合 float x float 上, 即 加法運算 有超載的情形。

對於 C++ 程式, 我們可以明確地定義超載函數, 同一個函數名稱, 只要函數的引數當中,個數不一, 或同名函數中相對應的引數中的資料型態不一, 即可定義不同的函數。

我們以例子來說明其使用法。

例 2 : overloaded functions

    int f(int a)
    {
        return a*a;
    }

    char f(char a)
    {
        return a+1;
    }

    int f(int a, int b)
    {
        return a*b;
    }

    main()
    {
        cout<< "f(2)="<< f(2)<< endl;
        cout<< "f('a')="<< f('a')<< endl;
        cout<< "f(2, 3)="<< f(2,3)<< endl;
    }

說明:

  1. 函數 f() 共有 3 種不同的定義。
  2. 該程式的結果為
    f(2)=4
    f('a')=b
    f(2, 3)=6
    

C++ 程式語言提供了函數的設計更有彈性, 即呼叫函數時, 實際的引數 個數 可以少於 形式引數的 個數。 欲達此功能, 只要在 函數的 定義中, 將 形式引數 加上 = 以及其起始值即可。 其使用方式以例 3 來說明。

例 3 : overloaded functions with initial values

    int f(int a=1, int b=2, int c=3)
    {
        return a*b*c;
    }
    main()
    {
        cout<< "f()="<< f()<< endl;
        cout<< "f(10)="<< f(10)<< endl;
        cout<< "f(10, 5)="<< f(10, 5)<< endl;
        cout<< "f(10, 5, 2)="<< f(10, 5, 2)<< endl;
    }
說明:
  1. 函數呼叫 f() 不含引數, 此時 a=1, b=2, c=3
  2. 函數呼叫 f(10) 僅含 1 個引數, 此時 a=10, b=2, c=3
  3. 函數呼叫 f(10, 5) 僅含 2 個引數, 此時 a=10, b=5, c=3
  4. 函數呼叫 f(10, 5, 2) 僅含 3 個引數, 此時 a=10, b=5, c=2
  5. 該程式的結果為
    f()=6
    f(10)=60
    f(10, 5)=150
    f(10, 5, 2)=100
    
於例 1 中 CStack 的 constructor CStack() 就可以設計的更具彈性, 如例 4 所示。

例 4 : overloaded constructor CStack()

     #define MAXSIZE 100
     class  CStack
     {   
        public:
            CStack(int n = MAXSIZE);
            ~CStack( );
            int  isEmpty( );
            int  isFull( );
            void  push(char c);
            char  pop( );
        private:
            char  *s;
            int  tos;
            int  size;
     }

     CStack::  CStack(int n = MAXSIZE)
     {  tos=0; size = n; s = new char[size]; }
     CStack::  ~CStack( ){ delete [] s; }

     int   CStack::  isEmpty( ){ return tos==0; }
     int   CStack::  isFull( ){ return tos==size; }
     void  CStack::  push(char c){ s[tos++]=c; }
     char  CStack::  pop( ){ return s[--tos]; }  

回本章主目錄


回第 10 章
至第 12 章
回 C 程式主目錄