您的位置:首頁>正文

深入淺出IO流

如果沒有iostream

如果沒有iostream, 那麼我們的第一個程式應該怎麼寫呢?如果有iostream, 我們的第一個程式成通常會是:

//+--------------------

#include

int main(){

std::cout<<"Hello World"<

return 0;

}

//+---------------------

這通常是我們學習C++最開始引入的程式, 這個程式依賴了C++標準庫的輸出流ostream的物件cout, 那麼問題來了, 如果我們自訂了一個類型, 簡單一點比如MyString, 那麼我們沒有理由不讓它支援列印這個操作, 這時候如果沒有iostream, 我們應該怎麼辦呢?順便推薦下我自己的C/C++學習群:598131849, 不管你是小白還是大牛, 小編我都挺歡迎, 不定期分享乾貨, 包括我自己整理的資料和零基礎入門教程, 送給大家, 歡迎初學和進階中的小夥伴。

//+-----------------------

class MyString{

//

// 實現細節

//

};

//+-----------------------

通常來說, 如果我們需要讓我們的類型支援流的的輸出, 那麼我們就會考慮如下的方式:

//+-----------------------

std::ostream& operator<<(std::ostream& os,const MyString& str)

//

// 實現細節

//

return os;

}

//+-------------------------

這種方式是我們常用的方式, 是每一個C++程式師必須第一時間掌握的實現方式, 下面我們會細說。 現在的問題是這個函數我們應該怎麼實現才能減少設計上帶來的耦合, 我們可以這麼做:

//+-------------------------

namespace std{

class ostream;

}

std::ostream& operator<<(std::ostream& os,const MyString& str);

//+-------------------------

注意, 我們這裡僅聲明不實現, 我們在其他的地方單獨定義該函數, 這樣可以減少我們的類型MyString對iostream的耦合, 但是在我們定義該函數的地方必須要包含iostream標頭檔, 否則ostream就是未定義的類, 當我們實現了這個函數之後, 我們便可這麼使用:

//+------------------------

#include "MyString.h"

#include

int main(){

MyString str = "Hello World";

std::cout<

return 0;

}

//+------------------------

這個問題解決了設計上的耦合問題, 但是並沒有解決上面我們所提出的問題:如果我們沒有iostream的話呢?

沒有iostream沒有關係, iostream依賴於C++標準庫, 但是有不依賴於C++ 標準庫的東西, 比如put系列函數, 該系列函數是C運行庫提供的函數, 由於C語言是很多程式設計語言的祖先, 而C++更是C的擴展, 所以在C++中使用C函數是毫無問題的, 但是此處使用put系列函數顯得太不C++, 當然可以對其進行封裝再使用——物件導向程式設計不就是這樣的嗎?到這一步, 我們可以來考慮使用類的概念來對put系列函數的封裝, 此處我們選擇使用putc, putc函數的作用是將一個字元寫進指定的檔中, 這剛好滿足我們的需求。

將資料寫進目標位址中, 秉著這一概念, 我們可以先為我們的io定義一個函數:

//+------------------------

void sendstr(FILE* fp,const char* str,int n)

for(int i=0;i

putc(*str++,fp);

}

}

//+-------------------------

現在回到我們的MyString上面:

//+-------------------------

class MyString{...};

FILE* operator<<(FILE* fp,const MyString& str)

sendstr(fp,str.c_str(),str.size());

return fp;

}

//+-------------------------

有了這個操作符之後我們便可以寫出下面的代碼:

//+-------------------------

int main(){

MyString str = "Hello World";

stdout<

return 0;

}

//+--------------------------

注意了,

我們這裡使用的是stdout而不是std::cout, stdout是C語言定義的標準輸出, 也就是控制台, 而std::cout是C++的ostream的物件, 目的地也是控制台, 他是對stdout的封裝。 回到我們上面的代碼, 這種寫法沒毛病, 但是很彆扭, 尤其在C++裡面, 所以我們應該嘗試對stdout進行封裝, 如下:

//+-------------------------

class MyStrIobase{

public:

virtual ~MyIobase(){}

virtual void send(const char* ptr,int n){}

};

//+------------------------

這是一個介面操作, 有了這個介面, 再加上我們上面的概念, 所以我們可以對sendstr進行擴展:

//+------------------------

void sendstr(MyStrIobase& strio,const char* ptr,int n)

strio.send(ptr,n)

}

//+------------------------

現在還沒法工作, 因為我們的MyStrIoBase啥都沒做, 如果我們想要做些什麼, 那麼就需要從MyStrIoBase派生出我們自己的類, 比如列印到控制台的OStream:

//+-----------------------

class OStream : public MyStrIobase{

public:

virtual void send(const char* ptr,int n){

for(int i=0;i

putc(*ptr++,stdout)

}

}

};

OStream gOut;

int main(){

MyString str = "Hello World";

gOut<

return 0;

}

//+--------------------

現在編譯上面的程式我們會到編譯錯誤, 沒有相應的操作符供我們使用, 不過這都不是事, 我們只需要擴展一下我們的operator<<操作符即可, 我們可以使用範本讓他做更多的事:

//+---------------------

template

T& operator<<(T& io,const MyString& str){

sendstr(io,str.c_str(),str.size());

return io;

}

//+--------------------

現在上面的代碼能夠正常工作了,

當我們運行程式會在黑乎乎的控制台上看到Hello World的輸出, 那麼如果我們想要使用std::ostream來輸出呢?這時候我們應該怎麼做呢?我們說了, 我們使用範本來實現operator<<操作符, 目的就是讓他可以做更多事, 所以對於std::ostream來說, MyString一樣可以支援, 只需要我們重載一個sendstr即可, 如下:

//+--------------------

void sendstr(std::ostream& os,const char* ptr,int n){

os.write(ptr,n);

}

int main(){

MyString str = "Hello World";

std::cout<

return 0;

}

//+--------------------

程式如同我們預期正常工作, 那麼, 現在我們再回過頭去看看我們的MyStrIobase,如果我們想要讓他對檔的支持, 那麼我們應該怎麼做呢?這些問題如果放到後面來說可能很簡單, 當然放在這裡說也是很簡單的, 我們對FILE*進行簡單的封裝即可:

//+--------------------

class FileOStream : public MyStrIobase{

public:

FileOStream(const char* fileName,const char* mode){

mFile = fopen(fileName, mode);

}

virtual void send(const char* ptr, int n){

if (mFile == nullptr)

return;

for (int i = 0; i < n; ++i){

putc(*ptr++, mFile);

}

}

void close(){

fclose(mFile);

mFile = nullptr;

}

private:

FILE* mFile{ nullptr };

};

int main(){

MyString str = "Hello World";

FileOStream out("text.txt","w+");

out << str;

out.close();

return 0;

}

//+---------------------

運行程式後我們便將字元寫進了檔之中。

-----------------------------------

iostream

到此, 我們對io的操作有了一個大概的瞭解, 接下裡我們深入的觀察一下iostream的工作原理,

我們還是從最簡單的開始:

//+----------------------

int main(){

std::cout<<"Hello World"<

return 0;

}

//+---------------------

當我們執行上面程式的時候會發現控制台上列印出Hello World字元, 同時游標移動到下一行的起始處。 我們用一句通俗的話來對這句代碼的描述:將"Hello World"塞進std::cout中, 然後std::endl操作std::cout, 有了前面的基礎, 我們要理解這句話不難, 程式是由左向右執行, 所以第一步的執行是如下的函數:

//---------------------

std::ostream& operator<<(std::ostream& os,const char* msg){

os.write(msg,strlen(msg));

return os;

}

//+--------------------

在執行完上面這句代碼之後返回std::cout,所以接下來執行的確實:std::cout<

//+-------------------

std::ostream& endl(std::ostrem& os){

os<<" ";

os.flush();

return os;

}

//+------------------

看到這裡是不是覺得C++很有趣呢?那麼問題來了, std::endl又是如何與流操作符聯繫上的呢?解決方式有很多, 這裡我們簡單的說一種方式:

//+-------------------

typedef std::function streamoperationtype;

std::ostream& operator<<(std::ostream& os,streamoperationtype fun){

return fun(os);

}

//+----------------

是不是很有意思……當然標準庫可不是這麼幹的, 這只是我個人這麼幹,但是思路應該是一致的,就算不一致,至少我們又知道了另一種解決方案。那麼,列印在控制台的操作是不是只有cout呢?當然不是,下面是vs中的iostream聲明的幾個流物件,w開頭的是針對unicode字元的流物件,常用的是cin和cout以及cerr,至於clog是用於輸出日誌的,它寫的目的地和cerr一樣都是stderr。

//+----------------

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 istream cin, *_Ptr_cin;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cout, *_Ptr_cout;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cerr, *_Ptr_cerr;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream clog, *_Ptr_clog;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wistream wcin, *_Ptr_wcin;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcout, *_Ptr_wcout;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcerr, *_Ptr_wcerr;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wclog, *_Ptr_wclog;

//+-----------------

在ostream裡面定義了處理內部資訊的輸出操作符:

//+----------------

...

ostream& operator<<(short);

ostream& operator<<(int);

ostream& operator<<(long);

ostream& operator<<(long long);

ostream& operator<<(unsigned short);

ostream& operator<<(unsigned int);

ostream& operator<<(unsigned long);

ostream& operator<<(unsigned long long);

ostream& operator<<(float);

ostream& operator<<(double);

ostream& operator<<(long double);

ostream& operator<<(bool);

ostream& operator<<(const void*);

ostream& put(char);

ostream& write(const char*,streamsize);

...

//+------------------

我們看到裡面缺少了對char的操作符,但是put和write可以簡單地寫出字元,所以就沒必要實現一個流操作符(這是C++之父所說,因為標準就是這麼定義),可以通過全域函數來實現:

//+------------------

ostream& operator<<(ostream& os,char ch){

os.put(ch);

return os;

}

ostream& operator<<(ostream& os,const char* msg){

os.write(msg,strlen(msg));

return os;

}

int main(){

char A('A');

cout<<"A = "<

}

//+--------------------

write可以將一段buffer寫到指定地方,所以換句話說,write除了寫字串之外還能夠將資料按照二進位的放寫進檔儲存起來。

我們再來看另一個細節:

//+-------------------

int main(){

cout<

}

//+-------------------

運行程式,我們得到的結果是1和0,那麼我們可不可以希望他輸出的是true和false,當然可以:

//+-------------------

#include

#include

int main(){

cout<

cout<

cout<

}

輸出結果:

1 0;

truefalse;

//+-------------------

boolalpha 在iomanip中定義,當使用他之後所有的bool類型操作將按照字元形式列印。

下面這個函數有點特殊:

//+-------------------

ostream& operator<<(const void*);

//+-------------------

但他卻讓我們列印指標成了可能,很多時候我們確實很需要列印指標,當我們需要追蹤一個物件的時候:

//+-------------------

int main(){

int* ptr = new int(10);

cout<<&p<<" "<

}

輸出結果:

0x7788ff450x7895f2ff

//+-------------------

對於內置的類型標準庫都為我們實現了流的操作符,那麼對於我們自訂的類型,如果我們有需要的話那就需要我們自行定義了,比如:

//+------------------

class MInt{

public:

MInt(int val):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

private :

int mVal;

};

int main(){

MInt a(10);

cout<

}

//+------------------

上面的程式沒法通過編譯,因為cout無法對MInt操作。

cout同樣沒有對char實現流操作符,但是卻提供了一個全域函數來操作char,讓char如同其他內置類型一樣可以使用流操作,這是一個思路,當然也是規則,重載流操作符的形式必須如下:

//+-----------------

ostream& operator<<(ostream& os,const T& other);

//+-----------------

上面的 T 是就是要操作的類型,針對上面的MInt,可以如下:

//+------------------

ostream& operator<<(ostream& os,const MInt& other){

os<

return os;

}

//+----------------

現在又一個問題來了,mVal是MInt的私有變數,所以是不能直接訪問的,但是除此之外又沒他發,當然可以給MInt提供一個介面讓他返回mVal,不過除此之外還是有其他辦法的——友元函數。

//+----------------

class MInt{

public:

MInt(int val):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

friend ostream& operator<<(ostream& os,const MInt& other);

private:

int mVal;

};

int main(){

MInt a(10);

cout<

}

//+---------------

現在一切ok,可以看到想像中的結果。

和ostream一樣,istream同樣針對內置類型都實現輸入流操作符。

//+---------------

istream& operator>>(short&);

istream& operator>>(int&);

istream& operator>>(long&);

istream& operator>>(long long&);

istream& operator>>(unsigned short&);

istream& operator>>(unsigned int&);

istream& operator>>(unsigned long&);

istream& operator>>(unsigned long long&);

istream& operator>>(float&);

istream& operator>>(double&);

istream& operator>>(long double&);

istream& operator>>(bool&);

istream& operator>>(void*&);

istream& get(char);

...

//+------------------

想要通過cin來初始化物件,我們只需要實現相應的函數即可,而這個函數的樣子如下:

//+------------------

template

istream& operator>>(T& val);

//+------------------

但是很多時候我們不能這樣寫,為什麼呢?回顧上面我們說過的ostream,或者簡單點總結一下:如果我們想要用一個物件去操作另一個物件,那麼該樣式如下:

//+------------------

template

T op(A a B b);

//+------------------

這個函數的意義我們可以簡單的理解為A使用op操作B返回T,按照這個思想我們來看看下面的聲明表示的意義:

//+------------------

template

T operator+(const T& left,const T& right); // 表示 T res = left + right;

template

T operator-(const T& left,const T& right); // 表示 T res = left - right;

template

T operator*(const T& left,const T& right); // 表示 T res = left*right;

template

T operator/(const T& left,const T& right); // 表示 T res = left/right;

....

//+--------------------

現在我們回頭來看看讓cin使用>>來操作我們的物件,cin對應的是上面我們的left,而我們自己的物件就是上面對應的right,而返回的物件依然還是cin,所以要實現這個功能我們只需要實現諸如下面類型的函數:

//+-------------------

template

istream& operator>>(istream& is,T& res);

//+-------------------

此處 T 表示我們想要表達的類型,當然都是一些複合類型,但是複合類型是由簡單類型組合而成,所以我們在具體實現的時候只要針對複合類型的資料成員進行cin即可,比如:

//+-------------------

class MInt{

public:

MInt(int val = 0):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

friend ostream& operator<<(ostream& os,const MInt& other){

os<

}

friend istream& operator>>(istream& is,MInt& out){

is>>out.mVal;

return is;

}

friend MInt operator+(const MInt& left,const MInt& right){

return MInt(left.mVal + right.mVal);

}

friend MInt operator-(const MInt& left,const MInt& right){

return MInt(left.mVal - right.mVal);

}

friend MInt operator*(const MInt& left,const MInt& right){

return MInt(left.mVal*right.mVal);

}

friend MInt operator/(const MInt& left,const MInt& right){

return MInt(left.mVal/right.mVal);

}

private:

int mVal;

};

int main(){

MInt a;

cin>>a;

cout<

MInt b = 10;

MInt c = a + b;

MInt d = c*a;

MInt e = d/c;

cout<

return 0;

}

//+-------------------

這一文章雖然在說iostream,但是內容卻不局限於iostream,和其他的C++書籍比起,我們可能比較超前了些,不過我覺得以這樣的方式開局應該是不錯的,我屬於這樣的人,在接觸到一門語言的時候首先考慮的是如何快如的建立交互,所以我們邊開始思考流操作符重載這些問題,當然這些操作符重載是C++所必須的知識點,但又是一個難點,所以這些內容還是不太適用於從沒接觸過程式設計的初學者,因為我們並沒有像教科書一般從基本類型開始,關於這一點,曾和同學討論過,他認為這種難度的東西會不會嚇退一部分人,我說不會,我們深入淺出的說,如果實在是對原理不甚清楚,但到後面知道怎麼簡單使用這也足夠了,並且之所以會認為我們的第一章的難度頗大,是因為我們這裡幾乎涵蓋了C++的大部分知識要點,比如操作符重載,操縱器連杆器這些高級知識等,但這不些僅僅是為了讓大家在C++的領域裡面不只是淺嘗輒止,不僅知其然而且更知其所以然,當然,這些東西後續會細說的。

這只是我個人這麼幹,但是思路應該是一致的,就算不一致,至少我們又知道了另一種解決方案。那麼,列印在控制台的操作是不是只有cout呢?當然不是,下面是vs中的iostream聲明的幾個流物件,w開頭的是針對unicode字元的流物件,常用的是cin和cout以及cerr,至於clog是用於輸出日誌的,它寫的目的地和cerr一樣都是stderr。

//+----------------

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 istream cin, *_Ptr_cin;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cout, *_Ptr_cout;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cerr, *_Ptr_cerr;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream clog, *_Ptr_clog;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wistream wcin, *_Ptr_wcin;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcout, *_Ptr_wcout;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcerr, *_Ptr_wcerr;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wclog, *_Ptr_wclog;

//+-----------------

在ostream裡面定義了處理內部資訊的輸出操作符:

//+----------------

...

ostream& operator<<(short);

ostream& operator<<(int);

ostream& operator<<(long);

ostream& operator<<(long long);

ostream& operator<<(unsigned short);

ostream& operator<<(unsigned int);

ostream& operator<<(unsigned long);

ostream& operator<<(unsigned long long);

ostream& operator<<(float);

ostream& operator<<(double);

ostream& operator<<(long double);

ostream& operator<<(bool);

ostream& operator<<(const void*);

ostream& put(char);

ostream& write(const char*,streamsize);

...

//+------------------

我們看到裡面缺少了對char的操作符,但是put和write可以簡單地寫出字元,所以就沒必要實現一個流操作符(這是C++之父所說,因為標準就是這麼定義),可以通過全域函數來實現:

//+------------------

ostream& operator<<(ostream& os,char ch){

os.put(ch);

return os;

}

ostream& operator<<(ostream& os,const char* msg){

os.write(msg,strlen(msg));

return os;

}

int main(){

char A('A');

cout<<"A = "<

}

//+--------------------

write可以將一段buffer寫到指定地方,所以換句話說,write除了寫字串之外還能夠將資料按照二進位的放寫進檔儲存起來。

我們再來看另一個細節:

//+-------------------

int main(){

cout<

}

//+-------------------

運行程式,我們得到的結果是1和0,那麼我們可不可以希望他輸出的是true和false,當然可以:

//+-------------------

#include

#include

int main(){

cout<

cout<

cout<

}

輸出結果:

1 0;

truefalse;

//+-------------------

boolalpha 在iomanip中定義,當使用他之後所有的bool類型操作將按照字元形式列印。

下面這個函數有點特殊:

//+-------------------

ostream& operator<<(const void*);

//+-------------------

但他卻讓我們列印指標成了可能,很多時候我們確實很需要列印指標,當我們需要追蹤一個物件的時候:

//+-------------------

int main(){

int* ptr = new int(10);

cout<<&p<<" "<

}

輸出結果:

0x7788ff450x7895f2ff

//+-------------------

對於內置的類型標準庫都為我們實現了流的操作符,那麼對於我們自訂的類型,如果我們有需要的話那就需要我們自行定義了,比如:

//+------------------

class MInt{

public:

MInt(int val):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

private :

int mVal;

};

int main(){

MInt a(10);

cout<

}

//+------------------

上面的程式沒法通過編譯,因為cout無法對MInt操作。

cout同樣沒有對char實現流操作符,但是卻提供了一個全域函數來操作char,讓char如同其他內置類型一樣可以使用流操作,這是一個思路,當然也是規則,重載流操作符的形式必須如下:

//+-----------------

ostream& operator<<(ostream& os,const T& other);

//+-----------------

上面的 T 是就是要操作的類型,針對上面的MInt,可以如下:

//+------------------

ostream& operator<<(ostream& os,const MInt& other){

os<

return os;

}

//+----------------

現在又一個問題來了,mVal是MInt的私有變數,所以是不能直接訪問的,但是除此之外又沒他發,當然可以給MInt提供一個介面讓他返回mVal,不過除此之外還是有其他辦法的——友元函數。

//+----------------

class MInt{

public:

MInt(int val):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

friend ostream& operator<<(ostream& os,const MInt& other);

private:

int mVal;

};

int main(){

MInt a(10);

cout<

}

//+---------------

現在一切ok,可以看到想像中的結果。

和ostream一樣,istream同樣針對內置類型都實現輸入流操作符。

//+---------------

istream& operator>>(short&);

istream& operator>>(int&);

istream& operator>>(long&);

istream& operator>>(long long&);

istream& operator>>(unsigned short&);

istream& operator>>(unsigned int&);

istream& operator>>(unsigned long&);

istream& operator>>(unsigned long long&);

istream& operator>>(float&);

istream& operator>>(double&);

istream& operator>>(long double&);

istream& operator>>(bool&);

istream& operator>>(void*&);

istream& get(char);

...

//+------------------

想要通過cin來初始化物件,我們只需要實現相應的函數即可,而這個函數的樣子如下:

//+------------------

template

istream& operator>>(T& val);

//+------------------

但是很多時候我們不能這樣寫,為什麼呢?回顧上面我們說過的ostream,或者簡單點總結一下:如果我們想要用一個物件去操作另一個物件,那麼該樣式如下:

//+------------------

template

T op(A a B b);

//+------------------

這個函數的意義我們可以簡單的理解為A使用op操作B返回T,按照這個思想我們來看看下面的聲明表示的意義:

//+------------------

template

T operator+(const T& left,const T& right); // 表示 T res = left + right;

template

T operator-(const T& left,const T& right); // 表示 T res = left - right;

template

T operator*(const T& left,const T& right); // 表示 T res = left*right;

template

T operator/(const T& left,const T& right); // 表示 T res = left/right;

....

//+--------------------

現在我們回頭來看看讓cin使用>>來操作我們的物件,cin對應的是上面我們的left,而我們自己的物件就是上面對應的right,而返回的物件依然還是cin,所以要實現這個功能我們只需要實現諸如下面類型的函數:

//+-------------------

template

istream& operator>>(istream& is,T& res);

//+-------------------

此處 T 表示我們想要表達的類型,當然都是一些複合類型,但是複合類型是由簡單類型組合而成,所以我們在具體實現的時候只要針對複合類型的資料成員進行cin即可,比如:

//+-------------------

class MInt{

public:

MInt(int val = 0):mVal(val){}

MInt(const MInt& other):mVal(other.mVal){}

friend ostream& operator<<(ostream& os,const MInt& other){

os<

}

friend istream& operator>>(istream& is,MInt& out){

is>>out.mVal;

return is;

}

friend MInt operator+(const MInt& left,const MInt& right){

return MInt(left.mVal + right.mVal);

}

friend MInt operator-(const MInt& left,const MInt& right){

return MInt(left.mVal - right.mVal);

}

friend MInt operator*(const MInt& left,const MInt& right){

return MInt(left.mVal*right.mVal);

}

friend MInt operator/(const MInt& left,const MInt& right){

return MInt(left.mVal/right.mVal);

}

private:

int mVal;

};

int main(){

MInt a;

cin>>a;

cout<

MInt b = 10;

MInt c = a + b;

MInt d = c*a;

MInt e = d/c;

cout<

return 0;

}

//+-------------------

這一文章雖然在說iostream,但是內容卻不局限於iostream,和其他的C++書籍比起,我們可能比較超前了些,不過我覺得以這樣的方式開局應該是不錯的,我屬於這樣的人,在接觸到一門語言的時候首先考慮的是如何快如的建立交互,所以我們邊開始思考流操作符重載這些問題,當然這些操作符重載是C++所必須的知識點,但又是一個難點,所以這些內容還是不太適用於從沒接觸過程式設計的初學者,因為我們並沒有像教科書一般從基本類型開始,關於這一點,曾和同學討論過,他認為這種難度的東西會不會嚇退一部分人,我說不會,我們深入淺出的說,如果實在是對原理不甚清楚,但到後面知道怎麼簡單使用這也足夠了,並且之所以會認為我們的第一章的難度頗大,是因為我們這裡幾乎涵蓋了C++的大部分知識要點,比如操作符重載,操縱器連杆器這些高級知識等,但這不些僅僅是為了讓大家在C++的領域裡面不只是淺嘗輒止,不僅知其然而且更知其所以然,當然,這些東西後續會細說的。

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示