前言
創(chuàng)新互聯(lián)建站是一家專業(yè)提供張店企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、HTML5建站、小程序制作等業(yè)務(wù)。10年已為張店眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡(luò)公司優(yōu)惠進(jìn)行中。
這是一篇C#開(kāi)發(fā)重新學(xué)習(xí)C++的體驗(yàn)文章。
作為一個(gè)C#開(kāi)發(fā)為什么要重新學(xué)習(xí)C++呢?因?yàn)樵贑#在很多業(yè)務(wù)場(chǎng)景需要調(diào)用一些C++編寫(xiě)的COM組件,如果不了解C++,那么,很容易。。。注定是要被C++同事忽悠的。
我在和很多C++開(kāi)發(fā)者溝通的時(shí)候,發(fā)現(xiàn)他們都有一個(gè)非常奇怪的特點(diǎn),都很愛(ài)裝X,都覺(jué)得自己技術(shù)很好,還很愛(ài)瞧不起人;但如果多交流,會(huì)發(fā)現(xiàn)更奇怪的問(wèn)題,他們幾乎都不懂代碼設(shè)計(jì),面向?qū)ο蠛蜆I(yè)務(wù)邏輯的代碼寫(xiě)的也都很爛。
所以,這次重溫C++也是想了解下這種奇異現(xiàn)象的原因。
C++重溫
首先打開(kāi)VisualStudio,創(chuàng)建一個(gè)C++的Windows控制臺(tái)應(yīng)用程序,如下圖:
圖中有四個(gè)文件,系統(tǒng)默認(rèn)為我打開(kāi)了頭文件和源文件的文件夾。
系統(tǒng)這么做是有意義的,因?yàn)閯倢W(xué)習(xí)時(shí),外部依賴項(xiàng),可以暫時(shí)不用看,而資源文件夾是空的,所以我們只專注這兩個(gè)文件夾就可以了。
作為一個(gè)C#開(kāi)發(fā),我對(duì)C++就是一知半解,上學(xué)學(xué)過(guò)的知識(shí)也都忘記的差不多了,不過(guò),我知道程序入口是main函數(shù),所以我在項(xiàng)目里先找擁有main函數(shù)的文件。
結(jié)果發(fā)現(xiàn)ConsoleTest.cpp文件里有main函數(shù),那么,我就在這個(gè)文件里開(kāi)始學(xué)習(xí)C++了,而且它的命名和我項(xiàng)目名也一樣,所以很確定,它就是系統(tǒng)為我創(chuàng)建的項(xiàng)目入口文件。
然后我打開(kāi)ConsoleTest.cpp文件,定義一個(gè)字符串helloworld,準(zhǔn)備在控制臺(tái)輸出一下,結(jié)果發(fā)現(xiàn)編譯器報(bào)錯(cuò)。。。只好調(diào)查一下了。
調(diào)查后得知,原來(lái),c++里沒(méi)有string類型,想使用string類型,只能先引用string的頭文件,在引用命名空間std,如下:
頭文件
頭文件到底是什么呢?
頭文件,簡(jiǎn)單來(lái)說(shuō)就是一部分寫(xiě)在main函數(shù)上面的代碼。
比如上面的代碼,我們將其中的引用頭文件和使用命名空間的代碼提取出來(lái),寫(xiě)進(jìn)pch.h頭文件;然后,我們得到代碼如下圖:
pch.h頭文件:
ConsoleTest.cpp文件:
也就是說(shuō),頭文件是用來(lái)提取.cpp文件的代碼的。
呃。。。好像頭文件很雞肋啊,一個(gè)文件的代碼為什么要提取一部分公共的?寫(xiě)一起不就好了!為什么要搞個(gè)文件來(lái)單獨(dú)做,多傻的行為啊!
好吧,一開(kāi)始我也的確是這么想的。
后來(lái)我發(fā)現(xiàn),頭文件,原來(lái)并不是單純的提取代碼,還是跨文件調(diào)用的基礎(chǔ)。
也就是說(shuō),ConsoleTest.cpp文件,想調(diào)用其他Cpp文件的變量,必須通過(guò)頭文件來(lái)調(diào)用。
比如,我新建一個(gè)test.cpp和一個(gè)test.h文件。
然后我在test.cpp中,定義變量test=100;如下:
#include "pch.h"#include "test.h"int test = 100;
接著我在test.h文件中再聲明下test變量,并標(biāo)記該變量為外部變量,如下。
現(xiàn)在,我在回到ConsoleTest.cpp文件,引用test.h文件;然后我就可以在ConsoleTest.cpp文件中使用test.cpp中定義的test變量了,如下:
如上述代碼所示,我們成功的輸出了test變量,其值為100。
到此,我們應(yīng)該了解到了,頭文件的主要作用應(yīng)該是把被拆散的代碼,扭到一起的紐帶。
----------------------------------------------------------------------------------------------------
PS:我在上面引用字符串頭文件時(shí),使用的引用方法是【#include <string>】;我發(fā)現(xiàn),引用該頭文件時(shí),并沒(méi)有加后綴.h;我把后綴.h加上后【#include <string.h>】,發(fā)現(xiàn)編譯依然可以通過(guò)。
簡(jiǎn)單的調(diào)查后得知,【#include <string>】是C++的語(yǔ)法,【#include <string.h>】是語(yǔ)法。因?yàn)镃++要包含所有C的語(yǔ)法,所以,該寫(xiě)法也支持。
Cin與Cout
Cin與Cout是控制臺(tái)的輸入和輸出函數(shù),我在測(cè)試時(shí)發(fā)現(xiàn),使用Cin與Cout需要引用iostream頭文件【#include <iostream>】,同時(shí)也要使用命名空間std。
在上面,我們提到過(guò),使用字符串類型string時(shí),需要引用頭文件string.h和使用命名空間std,那么現(xiàn)在使用Cout也要使用命名空間std。這是為什么呢?
只能推斷,兩個(gè)頭文件string.h和iostream.h在定義時(shí),都定義在命名空間std下了。而且,通過(guò)我后期使用,發(fā)現(xiàn)還有好多類和類型也定義在std下了。
對(duì)此,我只能說(shuō),好麻煩。。。首先,缺失基礎(chǔ)類型這種事,就很奇怪,其次不是一個(gè)頭文件的東西,定義到一個(gè)命名空間下,也容易讓人混亂。
不過(guò),對(duì)于C++,這么做好像已經(jīng)是最優(yōu)解了。
----------------------------------------------------------------------------------------------------
PS:Cin與Cout是控制臺(tái)的輸入和輸出函數(shù),開(kāi)始時(shí),我也不太明白,為什么使用這樣兩個(gè)不是單詞的東西來(lái)作為輸入輸出,后來(lái),在調(diào)查資料時(shí),才明白,原來(lái)這個(gè)倆名字要拆開(kāi)來(lái)讀。
讀法應(yīng)該是這樣的C&in和C&out,這樣我們就清晰明白的理解了該函數(shù)了。
define,typedef,指針,引用類型,const
define
首先說(shuō)define,define在C++里好像叫做宏。就定義一個(gè)全局的字符串,然后再任何地方都可以替換,如下:
也就是說(shuō),define定義的宏,在C++里就是個(gè)【行走的字符串】,在編譯時(shí),該字符串會(huì)被替換回最初定義的值。這。。。這簡(jiǎn)直就是編譯器允許的bug。。。
不過(guò),它當(dāng)然也有好處,就是字符串更容易記憶和理解。但是說(shuō)實(shí)話,定義一個(gè)枚舉一樣好記憶,而且適用場(chǎng)景更加豐富,所以,個(gè)人感覺(jué)這個(gè)功能是有點(diǎn)雞肋,不過(guò)C++好多代碼都使用了宏,所以還是需要了解起來(lái)。
typedef
typedef是一個(gè)別名定義器,用來(lái)給復(fù)雜的聲明,定義成簡(jiǎn)潔的聲明。
如上述代碼所示,我定義了一個(gè)結(jié)構(gòu)體kiba_Org,如果我要用kiba_Org聲明一個(gè)變量,我需要這樣寫(xiě)【struct kiba_Org korg】,必須多寫(xiě)一個(gè)struct。
但我如果用typedef給【struct kiba_Org korg】定義一個(gè)別名kiba,那么我就可以直接拿kiba聲明變量了。
呃。。。對(duì)此,我只能說(shuō),為什么會(huì)這么麻煩?。?!
以為這就很麻煩了嗎?NO?。?!還有更麻煩的。
比如,我想在我定義的結(jié)構(gòu)體里使用自身的類型,要怎么定義呢?
因?yàn)樵贑++里,變量定義必須按照先聲明后使用的【絕對(duì)順序】,那么,在定義時(shí)就使用自身類型,編譯器會(huì)提示錯(cuò)誤。
如果想要讓編譯器通過(guò),就必須在使用前,先給自身類型定義個(gè)別名,這樣就可以在定義時(shí)使用自身類型了。
呃。。。好像有點(diǎn)繞,我們直接看代碼。
如上述代碼所示,我們?cè)诙x結(jié)構(gòu)體之前,先給它定義了個(gè)別名。
那么,變量定義不是必須按照先聲明后使用的【絕對(duì)順序】嗎?為什么這里,又在定義前,可以定義別名了呢?這不是矛盾了嗎?
不知道,反正,C++就是這樣。。。就這么屌。。。
指針
指針在C++中,就是在變量前加個(gè)*號(hào),下面我們定義個(gè)指針來(lái)看看。
如上述代碼所示,我們定義了倆指針,int *ipointer和int* ipointer2??梢钥吹剑疫@倆指針的*一個(gè)靠近變量一個(gè)靠近聲明符int,但兩種寫(xiě)法都正確,編譯器可以編譯通過(guò)。
呃。。。就是這么屌,學(xué)起來(lái)就是這么優(yōu)雅。。。
接著,我們用取地址符號(hào)&,取出i變量的地址給指針,然后指針變量*ipointer中ipointer存儲(chǔ)的是i的地址,而*ipointer存儲(chǔ)的是518,如下圖:
那么,我們明明是把i的地址給了變量*ipointer,為什么*ipointer存儲(chǔ)的是518呢?
因?yàn)?。。。就是這么屌。。。
哈哈,不開(kāi)玩笑了,我們先看這樣一段代碼,就可以理解了。
如上述代碼所示,我把聲明和賦值給分開(kāi)了,這樣就形象和清晰了。
我們把i的地址給了指針(*ipointer)中的ipointer,所以ipointer存的就是i的地址,而*ipointer則是根據(jù)ipointer所存儲(chǔ)的地址找到對(duì)應(yīng)的值。
那么,int *ipointer = &i;這樣賦值是什么鬼?這應(yīng)該報(bào)錯(cuò)啊,應(yīng)該不允許把i的地址給*ipointer啊。
呃。。。還是那句話,就是這么屌。。。
->
->這個(gè)符號(hào)大概是指針專用的。下面我們來(lái)看這樣一段代碼來(lái)了解->。
首先我們定義一個(gè)kiba結(jié)構(gòu)體的實(shí)例,定義定義一個(gè)kiba結(jié)構(gòu)體的指針,并把kinstance的地址給該指針。
此時(shí),如果我想為結(jié)構(gòu)體kiba中的字段id賦值,就需要這樣寫(xiě)【(*kpointer).id = 518】。
我必須把*kpointer擴(kuò)起來(lái),才能點(diǎn)出它對(duì)應(yīng)的字段id,如果不擴(kuò)起來(lái)編譯器會(huì)報(bào)錯(cuò)。
這樣很麻煩,沒(méi)錯(cuò),按說(shuō),微軟應(yīng)該在編譯器中解決這個(gè)問(wèn)題,讓他*kpointer不用被擴(kuò)起來(lái)就可以使用。
但很顯然,微軟沒(méi)這樣解決,編譯器給的答案是,我們省略寫(xiě)*號(hào),然后直接用存儲(chǔ)地址的kpointer來(lái)調(diào)用字段,但調(diào)用字段時(shí),就不能再用點(diǎn)(.)了,而是改用->。
呃。。。解決的就是這么優(yōu)雅。。。沒(méi)毛病。。。
引用類型
我們先定義接受引用類型的函數(shù),如下。
如上述代碼所示,u經(jīng)過(guò)函數(shù)usage后,他的值被改變了。
如果我們刪除usage函數(shù)中變量i前面的&,那么u的值就不會(huì)改變。
好了,那么&符號(hào)不是我們剛才講的取地址嗎?怎么到這里又變成了引用符了呢?
還是那句話。。。就是這么屌。。。
呃。。。還有更屌的。。。我們來(lái)引用個(gè)指針。
如上述代碼所示,我定義了兩個(gè)結(jié)構(gòu)體變量kiunew,kiu,和一個(gè)指針*kiupointer,然后我把kiu的地址賦值給指針。
接著我把指針和kiunew一起發(fā)送給函數(shù)usagePointer,在函數(shù)里,我把指針的地址改成了kiunew的地址。
運(yùn)行結(jié)果如下圖。
可以看到,指針地址已經(jīng)改變了。
如果我刪除掉函數(shù)usagePointer中的【引用符&】(某些情況下也叫取地址符)。我們將得到如下結(jié)果。
我們從圖中發(fā)現(xiàn),不僅地址沒(méi)改變,賦值也失敗了。
也就是說(shuō),如果我們不使用【引用符&】來(lái)傳遞指針,那么指針就是只讀的,無(wú)法修改。
另外,大家應(yīng)該也注意到了,指針的引用傳遞時(shí),【引用符&】是在*和變量之間的,如果*&k。而普通變量的引用類型傳遞時(shí),【引用符&】是在變量前的,如&i。
呃。。。指針,就是這么屌。。。
const
const是定義常量的,這里就不多說(shuō)了。下面說(shuō)一下,在函數(shù)中使用const符號(hào)。。。沒(méi)錯(cuò),你沒(méi)看錯(cuò),就是在函數(shù)中使用const符號(hào)。
如代碼所示,我們?cè)谌雲(yún)nti前面加上了const修飾,然后,我們得到這樣的效果。
i在函數(shù)constusage,無(wú)法被修改,一但賦值就報(bào)錯(cuò)。
呃。。?;贑#,估計(jì)肯定不好理解這個(gè)const存在的意義了,因?yàn)槿绻幌敫模蛣e改啊,標(biāo)只讀這么費(fèi)勁干什么。。。
不過(guò)我們換位思考一下,C++中這么多內(nèi)存控制,確實(shí)很亂,有些時(shí)候加上const修飾,標(biāo)記只讀,還是很有必要的。
PCH
在項(xiàng)目創(chuàng)建的時(shí)候,系統(tǒng)為我們創(chuàng)建了一個(gè)pch.h頭文件,并且,每個(gè).cpp文件都引用了這個(gè)頭文件【#include "pch.h"】。
打開(kāi).pch發(fā)現(xiàn),里面是空代碼,在等待我們填寫(xiě)。
既然.pch沒(méi)有被使用,那么將【#include "pch.h"】刪掉來(lái)簡(jiǎn)化代碼,刪除后,發(fā)現(xiàn)編譯器報(bào)錯(cuò)了。
調(diào)查后發(fā)現(xiàn),原來(lái)項(xiàng)目在創(chuàng)建的時(shí)候,為我們?cè)O(shè)置了一個(gè)屬性,如下圖。
如圖,系統(tǒng)我們創(chuàng)建的pch.h頭文件,被設(shè)置成了預(yù)編輯頭文件。
下面,我修改【預(yù)編譯頭】屬性,修改為不使用預(yù)編譯頭,然后我們?cè)賱h除【#include "pch.h"】引用,編譯器就不會(huì)報(bào)錯(cuò)了。
那么,為什么創(chuàng)建文件時(shí),會(huì)給我們?cè)O(shè)置一個(gè)預(yù)編譯頭呢?微軟這么做肯定是有目的。
我們通過(guò)名字,字面推測(cè)一下。
pch.h是預(yù)編譯頭,那么它的對(duì)應(yīng)英文,大概就是PrecompileHeader。即然叫做預(yù)編譯,那應(yīng)該在正式編譯前,執(zhí)行的編譯。
也就是,編譯時(shí),文件被分批編譯了,pch.h預(yù)編譯頭會(huì)被提前編譯,我們可以推斷,預(yù)編譯頭是用于提高編譯速度的。
類
C++是一個(gè)同時(shí)面向過(guò)程和面向?qū)ο蟮木幊陶Z(yǔ)言,所以,C++里也有類和對(duì)象的存在。
類的基礎(chǔ)定義就不多說(shuō)了,都一樣。
不過(guò)在C++中,因?yàn)椋美щy的原因(上面已經(jīng)描述了,只能引用其他.cpp文件對(duì)應(yīng)的頭文件,并且,.cpp實(shí)現(xiàn)的變量,還得在頭文件里外部聲明一下),所以類的定義寫(xiě)法也發(fā)生了改變。
C++中創(chuàng)建類,需要在頭文件中聲明函數(shù),然后在.cpp文件中,做函數(shù)實(shí)現(xiàn)。
但是這樣做,明顯是跨文件聲明類了,但C++中又沒(méi)有類似partial關(guān)鍵字讓倆個(gè)文件合并編譯,那么怎么辦呢?
微軟給出的解決方案是,在.Cpp文件中提供一個(gè)類外部編寫(xiě)函數(shù)的方法。
下面,我們簡(jiǎn)單的創(chuàng)建一個(gè)類,在頭文件中聲明一些函數(shù)和一些外部變量,然后在.cpp文件中實(shí)現(xiàn)這些函數(shù)和變量。
右鍵頭文件文件夾—>添加——>類,在類名處輸入classtest,如下圖。
然后我們會(huì)發(fā)現(xiàn),系統(tǒng)為我們創(chuàng)建了倆文件,一個(gè).h頭文件和一個(gè).cpp文件,如下圖。
然后編寫(xiě)代碼如下:
classtest.h頭文件:
calsstest.cpp文件:
調(diào)用測(cè)試代碼如下:
結(jié)語(yǔ)
通過(guò)重溫,我得出如下結(jié)論。
一,C++并不是一門優(yōu)雅的開(kāi)發(fā)語(yǔ)言,他自身存在非常多的設(shè)定矛盾和混淆內(nèi)容,因此,C++的學(xué)習(xí)和應(yīng)用的難度遠(yuǎn)大于C# ;其難學(xué)的原因是C++本身缺陷導(dǎo)致,而不是C++多么難學(xué)。
二,指針是C++開(kāi)發(fā)學(xué)習(xí)設(shè)計(jì)模式的攔路虎,用C++學(xué)習(xí)那傳說(shuō)中的26種設(shè)計(jì)模式,還勉強(qiáng)可以;但,如果想學(xué)習(xí)MVVM,AOP等等這些的設(shè)計(jì)模式的話,C++的指針會(huì)讓C++開(kāi)發(fā)付出更多的代碼量,因此多數(shù)C++開(kāi)發(fā)對(duì)設(shè)計(jì)模式理解水平很低也是可以理解的了。
三,通過(guò)學(xué)習(xí)和反思,發(fā)現(xiàn),我曾經(jīng)接觸的那些愛(ài)裝X的C++開(kāi)發(fā),確實(shí)是坐井觀天、夜郎自大,他們的編寫(xiě)代碼的思維邏輯,確確實(shí)實(shí)是被C++的缺陷給限制住了。
----------------------------------------------------------------------------------------------------
到此,我重溫C++的心路歷程就結(jié)束了。
代碼已經(jīng)傳到Github上了,歡迎大家下載。
Github地址:https://github.com/kiba518/C-ConsoleTest
----------------------------------------------------------------------------------------------------
總結(jié)
以上所述是小編給大家介紹的一個(gè)C#開(kāi)發(fā)者重溫C++的心路歷程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
分享題目:一個(gè)C#開(kāi)發(fā)者重溫C++的心路歷程
鏈接分享:http://aaarwkj.com/article2/jpoooc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、網(wǎng)站內(nèi)鏈、微信小程序、面包屑導(dǎo)航、網(wǎng)站導(dǎo)航、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)