C++的iostream標准庫介紹(3)

  C語言提供了格式化輸入輸出的方法,C++也同樣,但是C++的控制符使用起來更爲簡單方便,在c++下有兩中方法控制格式化輸入輸出。
  1.有流對象的成員函數。
  例如,下列程序以成員函數的方式控制輸出的精度:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  using namespace std;
  
  int main()
  {
   float pi=3.14159f;
   cout<<pi<<endl;
   cout.precision(2);
   cout<<pi<<endl;
   system("pause");
  }
  2.使用C++輸入輸出控制符,控制符是在拖文件iomanip.h中定義的對象,與成員函數有一樣的效果,控制符不必像成員函數學那樣單獨調用,它可以直接插入流中使用。
  例如,下列程序以控制符的方式控制輸出的精度:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  #include <iomanip>
  using namespace std;
  
  int main()
  {
   float pi=3.14159f;
   cout<<pi<<endl;
   cout<<setprecision(4);
   cout<<pi<<endl;
   system("pause");
  }
  下表我們列出了一些比較常用的控制符號,由于篇幅有限讀者請根據自己的需要查閱相關書籍:
  對于iostream標准庫來說包含了衆多的成員函數,各函數都有其自身的作用,篇幅問題筆者在這裏不能一一說明例舉,由于標准輸入對象cin提供輸入的時候會自動以空格作爲分界,給我們獲取一行帶有空格的完整字符串帶來了困難,在這裏補充一個非常用有的成員函數----getline()。
  其函數原型爲:
  getlin(chiar *str,int size,char='\n');
  第一個參數是字符數組,用于存放整行文本,第二個參數讀取的最大字符個數,第三個參數爲作爲分界界限的字符,默熟悉是\n,換行符。
  示例代碼如下:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  #include <iomanip>
  using namespace std;
  
  int main()
  {
   char str[100];
   cin.getline(str,sizeof(str),'\n');
   cout<<str<<endl;
   system("pause");
  }
  通過上面內容的學習,我們對i/o有了一些基本點基本的熟悉,現在是該切入正題的時候了,具體學習一下,如何重載左移與右移操作符。
  先說左移(<<)操作符,也就是我們常說的輸出操作符。
  對于自定義類來說,重載左移操作符的方法我們常使用類的友元方式進行操作。
  示例代碼如下:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  using namespace std;
  
  class Test
  
   {
   public:
   Test(int age = 0,char *name = "\0")
   {
   Test::age = age;
   strcpy(Test::name,name);
   }
   void outmembers(ostream &out)
   {
   out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;
   }
   friend ostream& operator <<(ostream& ,Test&);
   protected:
   int age;
   char name[50];
  };
  ostream& operator <<(ostream& out,Test &temp)
  {
   temp.outmembers(out);
   return out;
  }
  int main()
  {
   Test a(24,"管甯");
   cout<<a;
   system("pause");
  }
  上例代碼中,我們對void outmembers(ostream &out)的參數使用ostream定義主要是爲了可以向它傳遞任何ostream類對象不光是cout也可以是ofstrem或者是ostrstream和ostringstream類對象,做到通用性。
  重載運算符,我們知道可以是非成員方式也可以是成員方式的,對于<<來說同樣也可以是成員方式,但我十分不推薦這麽做,因爲對于類的成員函數來說,第一個參數始終是會被隱藏的,而且一定是當前類類型的。
  下面的示例代碼就是將上面的<<重載函數修改成成員方式的做法:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  using namespace std;
  
  class Test
  {
   public:
   Test(int age = 0,char *name = "\0")
   {
   Test::age = age;
   strcpy(Test::name,name);
   }
   void outmembers(ostream &out)
   {
   out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;
  
   }
   ostream& operator <<(ostream &out)
   {
   this->outmembers(out);
   return out;
   }
   protected:
   int age;
   char name[50];
  };
  int main()
  {
   Test a(24,"管甯");
   a<<cout;
   system("pause");
  }
  從代碼實現上,我們將函數修改成了ostream& operator <<(ostream &out),迫不得已將ostream類型的引用參數放到了後面,這是因爲,成員方式運算符重載函數第一個參數會被隱藏,而且一定是當前類類型的,這和ostream類型沖突了。由此我們在使用cout輸出的時候就必須寫成a<<cout;,這樣一來代碼的可讀行就大大降低了,這到底是左移還是右移呢?爲此我再一次說明,對于左移和右移運算符的重載是十分不推薦使用成員函數的方式編寫的。
  爲了鞏固學習,下面我們以fstream對象輸出爲例做一個練習。
  代碼如下:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  #include <iostream>
  #include <fstream>
  using namespace std;
  
  class Test
  {
   public:
   Test(int age = 0,char *name = "\0")
   {
   Test::age = age;
   strcpy(Test::name,name);
   }
   void outmembers(ostream &out)
   {
   out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;
   }
   friend ostream& operator <<(ostream& ,Test&);
   protected:
   int age;
   char name[50];
  };
  
   ostream& operator <<(ostream& out,Test &temp)
  {
   temp.outmembers(out);
   return out;
  }
  int main()
  {
   Test a(24,"管甯");
   ofstream myfile("c:\\1.txt",ios::out,0);
   if (myfile.rdstate() == ios_base::goodbit)
   {
   myfile<<a;
   cout<<"文件創建成功,寫入正常!"<<endl;
   }
   if (myfile.rdstate() == ios_base::badbit)
   {
   cout<<"文件創建失敗,磁盤錯誤!"<<endl;
   }
   system("pause");
  }
  對于左移運算符重載函數來說,由于不推薦使用成員方式,那麽使用非成員方式在類有多重繼續的情況下,就不能使用虛函數進行左移運算符重載的區分,爲了達到能夠區分顯示的目的,給每個類分別添加不同的虛函數是必要的。
  示例代碼如下:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  #include <fstream>
  using namespace std;
  
  class Student
  {
   public:
   Student(int age = 0,char *name = "\0")
   {
   Student::age = age;
   strcpy(Student::name,name);
   }
   virtual void outmembers(ostream &out) = 0;
   friend ostream& operator <<(ostream& ,Student&);
   protected:
   int age;
   char name[50];
  };
  ostream& operator <<(ostream& out,Student &temp)
  {
  
   temp.outmembers(out);
   return out;
  }
  class Academician:public Student
  {
   public:
   Academician(int age = 0,char *name = "\0",char *speciality="\0"):Student(age,name)
   {
   strcpy(Academician::speciality,speciality);
   }
   virtual void outmembers(ostream &out)
   {
   out<<"Age:"<<age<<endl<<"Name:"<<name<<endl<<
   "speciality:"<<speciality<<endl;
   }
   protected:
   char speciality[80];
  };
  class GraduateStudent:public Academician
  {
   public:
   GraduateStudent(int age = 0,char *name = "\0",char *speciality="\0",
   char *investigate="\0"):Academician(age,name,speciality)
   {
   strcpy(GraduateStudent::investigate,investigate);
   }
   virtual void outmembers(ostream &out)
   {
   out<<"Age:"<<age<<endl<<"Name:"<<name<<endl<<
   "speciality:"<<speciality<<endl<<"investigate:"<<investigate<<endl;
   }
   protected:
   char investigate[100];
  };
  int main()
  {
   Academician a(24,"管甯","Computer Science");
   cout<<a;
   GraduateStudent b(24,"嚴燕玲","Computer Science","GIS System");
  
   cout<<b;
   system("pause");
  }
  在上面的代碼中爲了能夠區分輸出a對象與b對象,我們用虛函數的方式重載了繼續類Academician與多重繼續類GraduateStudent的outmembers成員函數,由于ostream& operator <<(ostream& out,Student &temp) 運算符重載函數是Student基類的,Student &temp參數通過虛函數的定義可以適應不同派生類對象,所以在其內部調用temp.outmembers(out); 系統可識別不同繼類的outmembers()成員函數。
  最後看一下,右移運算符的重載,右移運算符我們也常叫它輸入運算符號,對于它來說,具體實現和左移運算符的重載差別並不大,對于有多成員對象的類來說,只要保證能夠完整輸入各成員對象大數據就可以了。
  示例如下:
  //程序作者:管甯
  //站點:www.cndev-lab.com
  //所有稿件均有版權,如要轉載,請務必聞名出處和作者
  
  #include <iostream>
  using namespace std;
  
  class Test
  {
   public:
   Test(int age = 0,char *name = "\0")
   {
   Test::age = age;
   strcpy(Test::name,name);
   }
   void inputmembers(istream &out)
   {
   cout<<"please input age:";
   cin>>Test::age;
   cout<<"please input name:";
   cin>>Test::name;
   }
   friend istream& operator >>(istream& ,Test&);
   public:
   int age;
   char name[50];
  };
  istream& operator >>(istream& input,Test &temp)
  {
   temp.inputmembers(input);
   return input;
  }
  int main()
  {
   Test a;
   cin>>a;
  
   cout<<a.age<<""<<a.name<<endl;
   system("pause");
  }