1. 程式人生 > >一個demo學會c++程式設計

一個demo學會c++程式設計

這篇文章包含了c++的基本知識,起始並不適合0基礎程式設計師。如果你只是對c++的相關知識瞭解的沒有那麼全面,或者你或多或少遺忘了一部分基礎知識,那這篇文章再適合你不過了。如果有問題可以留言。

此demo主要包括三個檔案:namespace.h檔案,包含了自定義空間、空間函式、空間變數、空間自定義類;namespace.c檔案為namespace.h檔案中定義函式的實現;main.cpp檔案為主程式運算。

namespace.h和namespace.cpp包含了自定義基、繼承類、模板類的定義及實現。涉及到自定義類的建構函式、過載建構函式、函式預設值、解構函式、複製建構函式、過載運算子(賦值函式、加法函式)、虛擬函式、常值函式、靜態函式、靜態變數、常值變數、列舉變數、內部類、訪問修飾符、繼承、重寫虛擬函式、基類引用、不定引數函式、友函式、友類、型別引用、終態函式、終態類、模板變數等內容。

namespace.h檔案

#pragma once  //防止檔案被多重包含
#include <stdio.h>
#include <iostream>  //資料流
#include <string>  //字串
#include <exception>  //異常
#include <stdarg.h>  //變化引數
#ifndef PI   //如果沒有定義PI則定義,否則跳過  避免重複包含
#define PI 3.1415926
#endif
using namespace std;  //常用空間函式
//自定義名稱空間
namespace
mynamespace { //靜態整型 static long long timenow; //自定義函式 void myfun(string str); //自定義類-學生類 class Student { public: //公共成員,外部可以訪問的成員 Student(); //無參建構函式 //預設建構函式(引數全有預設值+無參函式)可以無參呼叫
Student(string name,int age=default_age); //有參建構函式 //函式名相同,方法過載,age含有預設引數,此引數可有可無 Student(int age); //有參建構函式 //函式名相同,方法過載,函式名相同,引數型別和數量不同的為過載,與返回值無關 virtual ~Student(); //解構函式 //銷燬物件時,自動呼叫該函式,該方法用來釋放記憶體,最好設為虛擬函式,這樣多型特性,能銷燬派生類物件建立的記憶體 Student(const Student& another); //複製建構函式 Student& operator=(const Student& another); //過載賦值運算子,在函式內生成類物件的就要返回類,沒有生成類物件的返回類引用 //可以過載關係運算符 算數運算子 遞增遞減運算子 按位運算 二元邏輯運算子 插入<<運算子 提取>>運算子 下標運算子 函式呼叫運算子 解除引用運算子 記憶體分配和釋放運算子 Student operator+(const Student& another) const; //加法運算子過載 Student的加法運算,const函式不改變類內成員,返回物件不返回引用是因為生成了一個新的物件,與原物件並列存在 Student operator+(const string& anothername) const; //加法運算子過載 避免過載時的隱式轉化 +必須在Student的後面。物件名稱既可以作為物件返回,又可以作為物件引用返回 virtual void setname(string name); //virtual關鍵字,虛擬函式,支援派生類重寫,最好所有函式都設定為虛擬函式,java就是這麼做的 string getname() const; //不改變資料成員的函式宣告為const void setage(int age); //常規函式宣告 static int getage(); //static關鍵字,靜態函式,靜態方法不能重寫,不存在繼承 //靜態方法屬於定義它的類的名稱,不屬於特定的物件,呼叫時使用名字解析 static string default_name; //靜態資料,儲存在靜態區 static const int default_age=18; //const關鍵字,常值資料,資料儲存在文字常量區,const資料定義時需要賦值。 //mutable標記的為可變變數 在const函式中可以改變值的變數 enum allsex{boy,girl}; //enum關鍵字,列舉型別,用於限定引數的取值範圍,相等於define,或者const class sex{ //定義內部類,性別 public: string getsex(); void setsex(allsex sextype); //使用列舉型別作為引數 private: string sexstr; }; protected: //派生類可以訪問的成員 string name; private: //只能在類內訪問的成員 int age; }; //派生類-班長類 class Monitor:public Student //公有繼承 public代表基類的最高訪問許可權 所有操作的許可權自動降級為此許可權 儘量使用public { public: Monitor(){ //建構函式不能繼承 this->task = "幫助老師管理班級"; //函式定義可以直接在宣告中實現,也可以在物件cpp中實現,也可以不實現,在呼叫時實現 name="monitor"; cout<<"無參派生類建構函式"<<endl; //cout<< <<endl; 輸出內容到dos視窗 }; virtual void setname(string name) override //override,重寫虛方法 virtual、override可以不寫,override寫上以便與隱藏函式混淆 { this->name=name; //this作為物件Student cout<<"派生類設定名稱引數:"+name<<endl; } using Student::getname; //包含基類函式,使用using關鍵字顯示的包含基類中定義的同名的所有版本的方法,包含後相當於在當前內中展開 string getname(string surname) //建立新成員函式,與基類形成過載 因為引數不同,若不使用using包含,則會隱藏基類函式 { cout<<"派生類獲取名稱引數:"+surname+name<<endl; return surname+name; } void setage() //隱藏基類函式,與基類函式同名 { age=7; cout<<"派生類設定年齡引數:"<<age<<endl; } int getage(){ //建立物件成員函式,基類中的函式為靜態函式,不屬於物件,屬於類 cout<<"派生類讀取年齡引數:"<<age<<endl; return age; }; string gettask(){return task;}; //建立物件成員函式 void settask(string task,...){ //...表示不定長的引數數目。建立物件成員函式 va_list arg_ptr; //定義引數列表 va_start(arg_ptr,task); //將引數列表起始位置繫結為第一個引數 string aa=" "; // while (aa!="" && !aa==NULL) //無法對引數列表個數或結尾進行判斷,必須自己傳入特性引數來代表個數或結尾 { aa = va_arg(arg_ptr,string); //迭代讀取引數,並轉化為相應的型別 } va_end(arg_ptr); //引數清理工作 this->task = task; }; private: int age; //基類中age為private,派生類無法訪問,派生類重新定義 string task; //新增派生類自有屬性 }; //自定義類-老師類 class Teacher { public: Teacher():name("teacher"),course("語文"){ //基類的預設建構函式,同時初始化資料成員name、course cout<<"基類無參建構函式:"+name<<endl; }; Teacher(string name){cout<<"基類有參建構函式:"+name<<endl;}; //基類的有參建構函式 ~Teacher(){cout<<"基類解構函式"<<endl;}; //解構函式 friend class Student; //友元,Student 類中所有的方法可以訪問Teacher的private、protected、public資料成員和方法 friend void Student::setname(string name); //只有設定友元的函式可以訪問當前類的成員和方法,只有Student:;setname函式可以訪問Teacher的成員方法 virtual Student& getstudent()=0; //=0代表為純虛擬函式,沒有定義方法,只是聲明瞭方法,包含純虛擬函式的類為抽象類,抽象類不能例項物件 virtual void setstudent(Student& students) =0; //&為引用,相當於變數別名 virtual string getname() final{ //final函式,禁止重寫,用在派生類再次被繼承後重寫的情況下; cout<<"基類獲取名稱引數:"+name<<endl;return name;}; virtual void setname(string name="teacher"){this->name = name;}; private: virtual string getcourse(){return course;}; //c++中,private函式也可以虛化重寫,java中只能重寫public和protect方法//繼承時可以修改訪問限制符 string name; protected: string course; }; //建立班主任類 class Headmaster final:public Teacher //final標記的類不能被繼承 { public: //using Teacher::Teacher; //建構函式不能繼承,只能顯示呼叫 Headmaster(){cout<<"派生類無參建構函式:headmaster"<<endl;}; //派生類的建構函式 呼叫前會自動呼叫基類的預設建構函式 Headmaster(string name):Teacher(name){ //派生類的建構函式,呼叫前會呼叫顯示引用的基類建構函式 cout<<"派生類有參建構函式:"+name<<endl; }; ~Headmaster(){cout<<"派生類解構函式"<<endl;}; //解構函式 //使用時,預設引數取值根據指標型別 函式方法根據指向物件 //virtual void setname(string name="headmaster") override; //派生類的建構函式 沒有using時 預設為重寫了所有版本 有using時,表示重寫了當前版本 派生類可以使用不同的預設引數 virtual Student& getstudent() override{return student;}; //記得新增override,因為基類改變,派生類沒改變會報錯,這樣提醒修改派生類 virtual void setstudent(Student& students) override{ //應該重寫,過載方法的,所有版本。虛擬函式可以不重寫,重寫不重寫都保持函式虛化特性 this->student = student;}; virtual string getcourse() override{return course;}; //重寫基類的private函式,並修改訪問修飾符 private: Student student; }; }; template<class TT=int> class classA{ //template<class T>為模板,型別T為不確定型別,classA為類模板,可以為不定型別設定預設值,但是在使用類定義示例時,仍然需要使用<> public: TT add(TT tt,TT pp); //使用模板函式 template<class TT> TT plus(TT tt,TT pp){ //在類模板內部定義函式 return tt+pp; } };

自定義空間namespace.app檔案

#pragma once  //防止檔案被多重包含
#include <stdio.h>
#include <iostream>  //資料流
#include <string>  //字串
#include "namespace.h"
using namespace std;
using namespace mynamespace;
void mynamespace::myfun(string str) 
{
    cout<<str<<endl;
}
//建構函式 //設定成員資料初始化值
Student::Student():name("student"),age(default_age)  
{
    cout<<"無參基類建構函式:"+name<<endl;
}
//建構函式
Student::Student(string name,int age)
{
    this->name=name;
    this->age = age;
    cout<<"有參基類建構函式:"+name<<endl;
}
//建構函式
Student::Student(int age)
{
    this->age = age;
    name="student";
    cout<<"有參基類建構函式:"+name<<endl;
}
//複製建構函式
Student::Student(const Student& another)
{
    name=another.name;
    age=another.age;
    cout<<"基類複製建構函式:"+name<<endl;
}
//賦值建構函式
Student& Student::operator=(const Student& another)
{
    //自賦值檢測
    if (this==&another)
    {
        return *this;
    }
    //釋放this原記憶體
    //賦值新記憶體
    name = another.name;
    age=another.age;
    cout<<"基類賦值建構函式:"+name<<endl;
    return *this;
}

//運算子過載
Student Student::operator+(const Student& another) const
{
    Student student;
    student.setname(name+" and "+another.name+"'s group");
    student.setage((age+another.age)/2);
    cout<<"基類加法運算子過載"<<endl;
    return student;
}
//運算子過載
Student Student::operator+(const string& anothername) const
{
    Student parents(anothername);
    cout<<"基類加字串運算子過載"<<endl;
    return parents;   //不能返回區域性物件的引用。  返回物件,會將區域性物件賦值給接收物件,再銷燬區域性物件。不銷燬指標記憶體。返回引用,將區域性引用賦值給接收引用,再銷燬區域性物件,則接收引用的內容也全部銷燬了。
}
void Student::setname(string name)   //無需重複使用virtual
{
    this->name=name;   //this作為物件Student
    cout<<"基類設定名稱引數:"+name<<endl;
}
string Student::getname() const
{
    cout<<"基類讀取名稱引數:"+name<<endl;
    return (*this).name;  //this是指標  可以取指向值
    //return name;
}
void Student::setage(int age)
{
    cout<<"基類設定年齡引數"<<endl;
    this->age=age;
}
int Student::getage()
{
    cout<<"基類共享靜態函式讀取年齡引數"<<endl;
    return default_age;   //靜態函式只能操作靜態資料
}
//解構函式   所以堆疊指標在函式退出時總是會自動釋放指向的堆中的記憶體。造成原記憶體損壞(呼叫函式)
Student::~Student()
{
    cout<<"基類解構函式:"+name<<endl;
    //這裡填寫釋放物件記憶體的函式
}

//巢狀類函式定義
string Student::sex::getsex()
{
    return sexstr;
}
//巢狀類函式定義
void Student::sex::setsex(allsex sextype)
{
    if (sextype==boy)
        sexstr = "boy";
    else
        sexstr = "girl";
}


//在類模板外部定義成員函式的方法為:template<模板形參列表> 函式返回型別 類名<模板形參名>::函式名(引數列表){函式體},
template<class TT> TT classA<TT>::add(TT tt,TT pp){ 
    return tt+pp;
}               



main.cpp檔案主要涉及標頭檔案引用、空間引用、結構體、類型別名、常值變數、全域性變數、常值函式、函式別名、函式指標、函式宣告、函式引數、行內函數、模板函式、時間函式、輸入輸出流、字串轉換、變數推導、類的指標和陣列、lambda表示式、智慧指標、型別向上轉型、輸入輸出檔案流、STL容器和演算法操作、陣列、向量、列表、堆疊、佇列、集合、對映、迭代器、搜尋演算法、分割槽演算法、排序演算法、操作演算法、字串正則表示式、多執行緒、執行緒安全、自定義字面量、變長模板等內容

主檔案main.cpp檔案

#pragma once                  //防止檔案被多重包含
#include <stdio.h>
#include <stdlib.h>
#include <chrono>             //正則表示式   vs2012後有
#include <iostream>           //資料流
#include <memory>             //記憶體操作
#include <fstream>            //檔案流
#include <string>             //字串
#include <regex>              //正則表示式
#include <exception>          //異常
#include <stdexcept>          //異常型別
#include <iterator>           //迭代器
#include <array>              //可獲取大小的固定陣列
#include <vector>             //資料結構  連續分佈的動態陣列
#include <list>               //不連續分佈的雙向連結串列
#include <deque>              //雙頭佇列
#include <queue>              //先入先出佇列
#include <stack>              //先入後出堆
#include <set>                //有序集合
#include <map>                //雜湊表
#include <algorithm>          //STL演算法
#include <numeric>            //數值計算演算法
#include <math.h>             //數值計算演算法
#include <functional>         //函式指標,將函式指標作為自定義函式引數   實現設定回撥函式
#include <thread>             //多執行緒庫   vs2012後有
#include <atomic>             //原子型別  執行緒安全  vs2012後有
#include <mutex>              //互斥體型別  vs2012後有
#include <time.h>             //時間型別
#include "namespace.h"        //自定義空間  ""先搜尋本地目錄  再遍歷全部  <>遍歷系統目錄     引用h檔案  相當於h檔案直接展開

using namespace std;                                                    //重用空間函式
using namespace mynamespace;                                            //自定義名稱空間   要避免不同空間下的同名變數函式衝突
struct People                                                           //自定義結構體
{
    string name;
    int age;
}People1;                                                               //People是型別,People1是變數
typedef int* intptr;                                                    //類型別名  typedef為已有型別宣告提供一個新的名稱  using有類似功能
const string studentname = "student";                                   //常量變數  任何不再名稱空間、函式、類中的名稱都被認為全域性作用
string stringtemp="";                                                   //全域性變數
const int getstudentnumber(){return 33;}                                //常量表達式
typedef void (*funtype)(string);                                        //定義函式指標型別  輸入string  返回void    等價於 using funtype = void (*)(string);。為了出現頻率高的程式碼,避免改動繁瑣性和書寫繁瑣性
//function<void(string)> function_pointer = printstring;                //函式指標
//void (*function_pointer)(string str)= printstring;                    //函式指標
void printstring(string str);                                           //函式宣告
void process(const vector<string>& vec,function<void(string)> fun);     //函式宣告
inline void sprintf1(string str){                                       //行內函數,編譯時在程式碼處展開,為讀使用頻率高,且程式碼量小的函式。避免改動繁瑣型和呼叫快捷性
    cout<<str<<endl;
}
void printstring(string str)                                            //自定義函式(列印輸出字串)
{
    cout<<str<<endl;
}
void process(const vector<string>& vec,function<void(string)> fun)      //自定義函式(呼叫函式fun,呼叫向量成員)
{
    for (auto& item:vec)
        fun(item);
}
template<class T> void print(T a)                                       //模板函式,函式模板通式
{
    cout<<a<<endl;
}
string Student::default_name = studentname;                             //類內靜態變數,無需建立物件,初始化需放在函式外全域性區域
int main()
{
    myfun("程式碼除錯者:欒鵬");                                          //呼叫自定義空間內函式,//兩個字串常量不能相加
    cout<<"============基本型別資料============"<<endl;                   //cout<<    <<endl列印輸出
    timenow = time(NULL);                                               //空間靜態變數,直接使用,此句返回的只是一個時間戳
    cout<<"當前時間戳"<<timenow<<"\n";                                   //時間戳表示指定時間點距離標準時間原點之間的秒數
    int* const temp = new int(0);                                       //const作用於左側的型別(作用於*指標),此處表示指向不變,若作用於int(const int*  var),表示指向的資料不變
    int& studentnumber = *temp;                                         //設定引用,引用不佔記憶體,不建立物件,只是別名
    cout<<"預設學生名稱為"+studentname+"\n";                           //cout中支援轉移字元,支援列印各種型別資料
    cout<<"預設班級人數為"<<(studentnumber = getstudentnumber())<<endl; //列印輸出,常量變數、呼叫常量表達式,endl是換行重新整理

    string str1 = to_string(std::min(studentnumber,22));                //其他型別轉化為字串。min和max被vs中windows.h定義為了巨集,導致庫裡面的正常函式沒法使用:
    string str2 = str1+"34";                                            //字串使用+合併,字串不能直接初始化為兩個常量字串相加。如果不能string str2 = "11"+"34";    
    studentnumber = (stoi(str2))/10;                                   //字串轉化為指定進位制的其他型別,stoi,stof,stod
    cout <<"算上班主任,班級人數:"<<studentnumber;
    cout.flush();                                                       //顯示重新整理資料流,寫入控制檯,不換行
    //float classtime = 45_min+50_s;                                    //呼叫自定義字面量,c++11後才有
    classA<int> initstr;                                                //定義模板類 <>內替換成需要的型別,                
    auto  int1=initstr.plus(3,2);                                       //自動變數型別,會去除const限定符和引用 
    decltype(int1) int2=0x11;                                           //型別借用,0x為16進製表示
    int int3=int1^int2;                                                 //補碼按位異或   即101與10001  按位異或為10100
    cout<<";其中男孩個數約"<<int3<<endl;                               //列印輸出

    classA<> initstr1;                                                  //使用預設型別引數

                                                                        //棧stack跟隨函式,一個函式,一個堆疊,相互不影響,自動釋放,一級快取,先進後出,記憶體限定  記憶體向下增長
                                                                        //堆heap,公共空間  手動釋放,二級快取儲存,連結串列結構,記憶體根據實體記憶體,記憶體向上增長。
                                                                        //全域性區、文字常量區、程式程式碼區   字元指標初始化的字串在常量,指標在棧上
    cout<<"============類的指標與陣列============"<<endl;
    Student* student=nullptr;                                           //指標定義初始化為空
    student = new Student;                                              //開闢指標記憶體   指標存在棧中  物件在堆中
    //student->age = 3;                                                 //私有成員  無法訪問
    //(*student).name = "小明";                                           //保護成員   無法訪問
    student->setname("小明");
    delete student;                                                     //釋放指標記憶體
    student = nullptr;                                                  //指標置空   防止野指標
    Student* students=nullptr;                                          //類指標定義,初始化為空
    students = new Student[3];                                          //開闢陣列記憶體
    delete[] students;                                                  //釋放陣列記憶體

    string namestr;
    int age;
    print("輸入學生姓名和年齡:");                                        //呼叫模板函式
    cin>>namestr>>age;                                                  //獲取從視窗輸入的資料,分別放在namestr變數和age變數中
    auto vlambda = [namestr](int age){                                  //lambda表示式,函式名代替函式體展開  []內為捕獲變數  ()內為引數,在沒有引數時可以不加()
        cout<<"建立學生結構體:名稱:"+namestr<<";年齡:"<<age<<endl;
    };  
    vlambda(age);                                                       //展開vlambda函式




    cout<<"============學生,基類操作============"<<endl;
    Student student1("曉剛");                                         //在堆疊中建立物件
    student1.setname("小剛");                                         //呼叫類內函式,在棧上使用物件
    Student* student2 = new Student("曉紅",7);                            //使用new 開闢的記憶體在堆上,指標在棧上,需要程式碼釋放在堆上的物件
    student2->setname("小紅");                                            //在堆上使用物件
    Student student3(student1);                                         //呼叫複製建構函式,即複製一個物件,
    Student& student4 = student3;                                       //設定引用,引用不建立物件,只是別名
    student4 = *student2;                                               //賦值建構函式
    student4.setname("小劉");
    Student student5 = student1+student4;                               //過載加法運算子
    student5 = student3+"小韓";                                           //過載加法運算子
    cout<<"學生列表:"+student1.getname()
        <<+"、"+student2->getname()
        <<"、"+student3.getname()
        <<"、"+student4.getname()
        <<"、"+student5.getname()<<endl;
    delete student2;                                                    //釋放記憶體,會呼叫解構函式。只有通過new開闢了記憶體的才需要釋放,否則會自動釋放
    student2 = nullptr;                                                 //指標置空,避免野指標
    auto student6 = unique_ptr<Student>();                              //使用智慧指標,指標銷燬時會自動銷燬指向記憶體,在try catch中不用擔心出錯而指標記憶體洩漏





    cout<<"============班長派生類操作============"<<endl;
    Monitor monitor;                                                    //生成派生類,會先呼叫基類建構函式,再呼叫派生類建構函式
    Student student11 = monitor;                                        //派生類轉化為基類,產生截斷,這裡呼叫的是基類的建構函式
    //指向派生類物件的基類指標,可以呼叫派生類重寫的虛擬函式、基類中的非虛擬函式、基類的預設引數、基類中未被重寫的虛擬函式(被派生類繼承默認了)
    Student& student12 = monitor;                                       //引用指向派生類物件,派生類轉為基類,不產生截斷。引用定義時需要初始化,引用不可改變
    student12.setname("小明");                                            //呼叫派生類重寫的虛擬函式
    student12.getname();                                                //呼叫基類函式
    student12.getage();                                                 //靜態函式,所有物件共享
    Student::getage();                                                  //靜態函式,可通過型別名稱呼叫
    monitor.getname("王");                                               //呼叫派生類的新增函式
    monitor.getname();                                                  //呼叫派生類包含的基類函式,不包含沒法呼叫
    monitor.setage();                                                   //呼叫派生類覆蓋的函式
    monitor.getage();                                                   //





    cout<<"============老師型別操作============"<<endl;
    Teacher* teacher = nullptr;                                         //抽象類不能例項化物件,但是可以建立指標                                                   
    teacher = new Headmaster();                                         //抽象類的子類可以例項化物件   因為子類重寫了所有純虛擬函式,使得子類成為非抽象類
    teacher->getname();                                                 //指標可以呼叫基類的方法,因為存在宣告  但是實現方法是不一定   因為不同派生類寫入方法不同
    delete teacher;                                                     //基類指標
    Headmaster Headmaster1("劉家航班主任");                               





    cout<<"============流操作============"<<endl;

    ifstream infile("input.txt", std::ios::in);                                     //輸入檔案流ifstream  輸出檔案流  ofstream   fstream雙向檔案流同時讀寫檔案
    ofstream outfile("output.txt",ios_base::trunc);                     //app寫之前移動到檔案尾,ate開啟後移動到檔案尾,binary二進位制模式輸入輸出
                                                                        //in從頭開始讀   out從頭開始寫   trunc開啟刪除已有資料
    if (outfile && infile)
    {
        try                                                             //try{}catch(){}  嘗試執行某段程式碼
        {
            infile.tie(&outfile);                                       //將輸入流與輸出流繫結,輸入流會自動重新整理至輸出流,兩個輸出流也可以繫結,實現同步
            string readstr;
            infile>>readstr;                                            //讀入資料流  資料流同時進入輸出流
            outfile<<readstr;                                           //再一次寫入字串
            ios_base::streampos curpos = outfile.tellp();               //獲取標記位置,輸出流tellp,輸入流tellg
            if (10==curpos)                                             //這裡等號兩邊緩過來會報錯
            {
                                                                        //輸出流seekp,輸入流seekg //iso_base::end流的結尾,iso_base::beg流的開始,iso_base::cur流的當前位置
                outfile.seekp(-2,ios_base::end);                        //-2表示指定流位置前面2個位置
                outfile<<0;
                outfile.close();
            }

            char line[1024]={0};                                        //按行讀取檔案
            while(infile.getline(line, sizeof(line))) 
            {
            }
        }
        catch (const exception err)                                     //丟擲異常並不一定遵循異常列表,java只能丟擲異常列表中的異常
        {                                                               //c++中的所有異常都是exception的派生  所以丟擲exception 沒有針對性
            cout<<"異常描述:"<<err.what()<<endl;                        //所有異常類都有.what(),異常描述函式
        }
        catch (...)                                                     //匹配所有異常          
        {                                                               //try catch 中異常類不需要字串設定建構函式 throw需要字串設定異常類的建構函式
            throw invalid_argument("無法開啟檔案");                     //丟擲invalid_argumenty異常  除exception的所有異常類都需要字串設定建構函式
        }
    }else
        cout<<"檔案不存在"<<endl;





    cout<<"============STL容器和演算法操作============"<<endl;            //STL  4類16大容器
                                                                        //順序容器  vector、deque、list、forward_list、array
                                                                        //關聯容器map、multimap、set、multiset
                                                                        //無序關聯容器或雜湊表 unordered_map、 unordered_multimap、unordered_set、unordered_multiset
                                                                        //容器介面卡  queue、priority_queue、stack
    //容器:一定資料結構的資料集;分配器:資料元素的記憶體管理;元素迭代器iterator:容器元素的訪問(指向元素的指標);演算法:資料運算
    array<string,3> allstr0 = {"name1","name2","name3"};                //可獲取大小的固定陣列
    vector<string> allstr1=vector<string>(10);                                              //連續分佈的動態陣列
    list<string> allstr2;                                               //不連續分佈的雙向連結串列
    deque<string> allstr3;                                              //連續分佈的雙頭佇列
    queue<string> allstr4;                                              //先入先出的佇列
    stack<string> allstr5;                                              //先入後出的棧
    set<string>  allstr6;                                               //有序的元素唯一的集合
    multiset<string> allstr7;                                           //有序的元素不唯一的集合
    map<string,int>   map_student;                                      //multimap支援重複鍵值
    map_student.insert(pair<string,int>("小明",12));                  //map的插入

    string allnamestr[]={"小明","小王","小剛","小紅","小劉"};
    vector<string> allstudent(allnamestr, allnamestr+5);                //陣列轉化為向量
    //allstudent.assign(5,"studentname");                               //動態分配記憶體
    vector<string> allteacher(2);                                       //定義字串向量;
    allteacher[0]="王老師";
    allteacher[1]="張老師";
    if (allstudent!=allteacher)                                         //向量==或!=進行了過載
    {
        allstudent.push_back("小張");                                 //尾部新增元素
        allstudent.pop_back();                                          //尾部刪除元素
        auto iter = begin(allstudent);                                  //獲取首部
        allstudent.insert(iter,"小李");                                   //在指定位置插入元素
        iter++;                                                         //相當於指標++
        *iter = "小陳";
        allstudent.erase(iter);                                         //在指定位置刪除元素  刪除後iter不能繼續使用了
        for (vector<string>::iterator iter1 = begin(allstudent);iter1!=end(allstudent);++iter1)
        {
            cout<<*iter1<<endl;
        }
        for (const auto& iter2:allteacher)                              //迭代器引用,反向迭代器rbegin(vectorstr1),insert_iterator插入迭代器,move_iterator移動迭代器
        {
            cout<<iter2<<endl;
        }
    }
    process(allstudent,[](string str){cout<<str<<endl;});               //使用lambda設定遍歷的回撥函式
    process(allteacher,printstring);                                    //自定義函式作為引數傳遞

    int sum=0;
    vector<int> vectorint1(10,1);
    auto it = find_if_not(begin(vectorint1),end(vectorint1),[](int i){return i<8;});    //搜尋演算法
    for_each(begin(vectorint1),end(vectorint1),[&sum](int i){sum+=i;});                 //操作演算法,每個元素執行回撥函式
    partition(begin(vectorint1),end(vectorint1),[](int i){return i%2;});