久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4814|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

如何學(xué)習(xí)C++(面向過程編程)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:101489 發(fā)表于 2016-1-3 02:21 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
C++支持3種編程方法即“面向過程編程”、“泛型編程”和“面向?qū)ο缶幊獭薄U莆者@3中編程方法,就能夠?qū)W好C++。
這篇日志談?wù)勅绾斡肅++進(jìn)行面向過程編程。
C語言的編程方式就是面向過程編程,將C++與C對(duì)比起來學(xué)習(xí)是掌握C++面向過程編程的一種捷徑。
對(duì)比1:基本語法
在基本語法上C++和C語言是相同的,C語言有的語法C++都有,而C++有的語法C語言基本全有。如果不考慮泛型編程和面向?qū)ο缶幊,C++在基本語法上與C語言無區(qū)別。因此學(xué)習(xí)過C語言的程序員,可以直接跳過C++基本語法的學(xué)習(xí)。
對(duì)比2:基本數(shù)據(jù)類型
所謂基本數(shù)據(jù)類型是指int、float、double等這些類型。相對(duì)于C語言,C++增加了bool型。bool型只有兩個(gè)值true和false,分別表示真和假。
其通常使用的方式如下:
bool flag=(x>10);
if(flag)
   printf("x>10");
else
   printf("x<=10");
當(dāng)然這是一個(gè)示例,實(shí)際的情況可能要復(fù)雜得多。bool型可以賦值為整型。
例如:
bool flag=10;
bool flag=-10;
bool flag=0;
只要賦值的整型不是0,那么bool型的值就是true,反之是false。
對(duì)比3:static變量
C++允許將局部變量定義為static。例如:
int fun()
{
    static int x=0;
    x++;
   return x;
}
如果按照下列方式調(diào)用該函數(shù):
fun();
fun();
int x=fun();
問x的值是多少?
答案是3。
其原因在于,一旦一個(gè)變量被聲明為static,則該變量一直存在于函數(shù)的局部,而不會(huì)在函數(shù)退出時(shí)銷毀。故此按照上述調(diào)用實(shí)際上執(zhí)行了三次x++。
static變量的引入是為了解決全局變量的過度使用。如果C語言沒有static變量,那么程序只能這么寫。
int x;
int fun()
{
    x++;
    return x;
}
此時(shí)x是一個(gè)全局變量。
對(duì)比4:變量初始化
C++允許一種新的變量初始化方法,如下:
int a(10);
此語句與C語言中的:
int a=10;
等價(jià)。
引入這種新語法的原因是為了與對(duì)象的初始化統(tǒng)一。例如:
ifstream f("c:\\test.txt");
該語句定義了對(duì)象f,f是一個(gè)輸入文件流對(duì)象(關(guān)于對(duì)象的問題后面再談)。由于對(duì)象的初始化只能采用上面的方式,因此索性引入了
int a(10);
這樣的語法。否則傻瓜編譯器可能就要出現(xiàn)二義性錯(cuò)誤了。
換言之,這種新語法完全可以不用,用也沒有壞處,反正編譯器認(rèn)識(shí)。
對(duì)比5:默認(rèn)函數(shù)參數(shù)
int fun(int x=0)
{
    x++;
    return x;
}
上述函數(shù)使用了默認(rèn)參數(shù),即給參數(shù)x一個(gè)默認(rèn)值0。調(diào)用函數(shù)時(shí)
int y=fun();
int y=fun(0);
兩者的結(jié)果完全等價(jià),y的值都是1。而
int y=fun(10);
調(diào)用的結(jié)果就是11。
對(duì)比6:引用
下列代碼中,b稱為a的引用。
int a=10;
int &b=a;
此時(shí)若執(zhí)行如下代碼:
b=b+10;
請(qǐng)問a的值是多少?答案是20。
為什么修改b,同時(shí)也會(huì)修改a呢?因?yàn)閎是a的引用。也就是b和a是同一個(gè)東西。
上述代碼可以換成指針形式,即:
int a=10;
int *b=&a;
*b=*b+10;
其結(jié)果仍然是把a(bǔ)修改為了20。
那么為什么要引入引用呢?因?yàn)?font color="#ff0000">引用比指針更加安全。如果我們使用指針,那么就可能出現(xiàn)下面的情況:
int a=10;
int *b=&a;
b=b+10;
這個(gè)程序員把代碼寫錯(cuò)了,但是編譯器并不會(huì)發(fā)出任何警告。因?yàn)樵诰幾g器眼中,這個(gè)代碼是完全正確的。
b=b+10;
意味著b指向的地址后移10,此時(shí)b已經(jīng)不再指向a,而指向了一個(gè)我們不知道的位置。如果把這個(gè)代碼改成下面的形式,結(jié)果更是災(zāi)難性的。
int a=10;
int *b=&a;
b=b+10;  //本意是寫*b=*b+10,因?yàn)槭韬鐾浟?
*b=100;
按照程序員的本意,此時(shí)a和b都應(yīng)該變成100。但很遺憾上述代碼不僅a仍然是10,并且還修改了一個(gè)不確定位置的值為100。若修改的位置正好是你的銀行存款,原本的數(shù)字是10000000,而現(xiàn)在修改為了100,你甚至都不知道是怎么修改的。你說這不是災(zāi)難性的嗎?
如果將指針改為引用,情況就好得多了。
換言之指針類型可以直接操作地址值,而引用是不行的。
引用的另外一個(gè)特點(diǎn)是不允許空引用。例如
int&b;
這樣的聲明就是錯(cuò)誤的,而指針是可以為空的。
int *b;
是合法的。
扯一句題外話,java的引用和C++的引用也是不同的。java的引用是可以為空的。因此java的引用類型等價(jià)于C++不允許修改地址的指針。
引用的一個(gè)重大用途是用于參數(shù)傳遞。先看下列代碼:
int fun(vector<int> v)
{
 v[0]++;
 return v[0];
}

int main()
{
 vector<int> v(3);
 v[0]=1;
 v[1]=2;
 v[2]=3;

 int y=fun(v);
 return 0;
}
其中vector是C++標(biāo)準(zhǔn)庫中的新類型。大家可以先把它認(rèn)為是數(shù)組。
上述代碼,將v傳遞到fun中,并在其中將0號(hào)元素++后返回。程序看似沒有問題,但實(shí)際上隱藏了巨大的隱患。
vector<int> v(300000000);
v[0]=1;
v[1]=2;
v[2]=3;
.....
v[300000000]=....;
 int y=fun(v);

把程序修改成上面就可以看出問題了。問題在于v的大小為300000000,這個(gè)長(zhǎng)度簡(jiǎn)直是太大了。但調(diào)用fun的時(shí)候,編譯器會(huì)將v拷貝一份,然后將這個(gè)拷貝傳遞到函數(shù)fun?梢韵胂笠幌逻@么大的一個(gè)數(shù)據(jù),拷貝是不是要花時(shí)間?拷貝是不是要消耗內(nèi)存?怎么避免這個(gè)問題呢?
事實(shí)上C語言可以用指針解決這個(gè)問題,代碼修改后如下
int fun(vector<int> *v)
{
 (*v)[0]++;
return (*v)[0];
}

int main()
{
vector<int> v(3);
v[0]=1;
v[1]=2;
v[2]=3;

int y=fun(&v);
return 0;
}
此時(shí)函數(shù)調(diào)用時(shí)傳遞的就是指針,不再是整個(gè)值,也就不存在拷貝的問題。用引用同樣可以解決這個(gè)問題。
int fun(vector<int> &v)
{
   v[0]++;
   return v[0];
}

int main()
{
vector<int> v(3);
v[0]=1;
v[1]=2;
v[2]=3;

int y=fun(v);
return 0;
}
從代碼上看是不是引用更友好一些呢?
但是我們也發(fā)現(xiàn)引用和指針有一個(gè)副作用,那就是v[0]的值會(huì)在fun中被修改。因此代碼應(yīng)該修改一下:
int fun(vector<int> &v)
{
   return v[0]+1;
}

但我們知道程序員是會(huì)犯錯(cuò)誤的,盡管我們知道應(yīng)該如此寫,但也許一不小心就犯錯(cuò)了。有解決的辦法嗎?那就是給引用加上const。
對(duì)比7:const變量
C++引入了const關(guān)鍵字,用于定義常量。例如:
const int a=10;
此時(shí)a稱為一個(gè)整型常量,即a的值不能修改,若修改則編譯器會(huì)報(bào)錯(cuò)。
在參數(shù)傳遞時(shí)可以為參數(shù)加上const,以避免參數(shù)被修改。如下:
int fun(const vector<int> &v)
{
    v[0]++;    //此處將報(bào)錯(cuò)
   return v[0];
}

const的另一個(gè)有趣問題在于const放的位置。
const int a=10;
int const a=10;
都是合法的。那么在使用上有區(qū)別嗎?也沒有區(qū)別,都是int常量。可是如果將int換成引用或者指針情況就大不一樣了。
cont int *a;  //常量指針,a指向的類型為const int, a的類型為*
int const *a; //常量指針,a指向的類型為int const  , a的類型為*
int* const a; //指針常量,a指向的類型為int, a的類型為*const
const int* const a; //指向常量的指針常量,a指向的類型為const int, a的類型為*const
有了*號(hào)之后組合數(shù)量猛增,那么引用情況也是類似的
const int &a; //常量引用,a引用的類型為const int, a的類型為&
int const &a; //常量引用,a引用的類型為int const, a的類型為&
int& const a; //引用常量,a引用的類型為int, a的類型為&  const
const int& const a; //指向常量的引用常量,a引用的類型為const int, a的類型為& const
對(duì)初學(xué)者而言這實(shí)在是很復(fù)雜,不過了解一下編譯器的原理,就很容易搞清楚。
說白了上面的代碼都是在定義變量a,a是引用或者指針,引用就是&,指針就是*。對(duì)于引用或者指針,那么都有引用或者指向的變量類型。
以“&”和“*”為分隔符,“&”和“*”前面的就是引用或者指向的變量類型。
而在“&”和“*”之后的符號(hào)則說明,變量a本身是不是一個(gè)const。
搞明白了這樣的原則,那么下面的類型就不是很變態(tài)了。
const int** &const a;
通常如此變態(tài)的用法只有在考試時(shí)出現(xiàn),如果是在實(shí)際項(xiàng)目中誰敢這么用,那么就有開除的風(fēng)險(xiǎn)了。
對(duì)比8:new和delete
new和delete是非常重要的操作符,用于動(dòng)態(tài)內(nèi)存管理。C語言里面有malloc和free兩個(gè)函數(shù)與之對(duì)應(yīng)。
但很多C語言課程講到malloc和free的時(shí)候都直接跳過不講,很多學(xué)習(xí)C語言的學(xué)生也通常沒有學(xué)習(xí)過內(nèi)存管理。
因此new和delete盡管很重要但很多學(xué)生在大學(xué)四年內(nèi)都無法掌握,盡管這是實(shí)際應(yīng)用中非常重要的。
這也難怪,如果我們總是做一些計(jì)算水仙花數(shù)的題目,是不需要用到內(nèi)存管理的。
假設(shè)現(xiàn)在有一個(gè)需求:將硬盤上的50MB的數(shù)據(jù)讀取到程序中,并保存在變量a里面。
我們不管怎么讀取硬盤數(shù)據(jù),僅考慮變量a應(yīng)該怎么定義。
  unsigned char  a[1024*1024*50];   //事實(shí)上這么寫可能會(huì)出錯(cuò),因?yàn)榭赡懿辉试S定義這么大的數(shù)組哦
應(yīng)該是這樣吧,一個(gè)unsigned char是8位,也就是1個(gè)byte,1024*1024*50個(gè)byte剛好50MB。
現(xiàn)在考慮一個(gè)復(fù)雜的情況,如果文件的大小事不確定的,又應(yīng)該如何定義變量呢?
unsigned char a[SIZE];
其中SIZE表示文件的大小(字節(jié)數(shù)),但問題在于我們根本不知道SIZE有多大。如果SIZE是一個(gè)變量,上述定義是無法編譯的。
因此就必須有一種動(dòng)態(tài)分配內(nèi)存的機(jī)制:
unsigned char *a=new unsigned char[SIZE];
此處的SIZE可以是一個(gè)變量。
我們看看下面代碼的執(zhí)行效果:
unsigned char *a=new unsigned char[1024*1024*50];
while(true);
動(dòng)態(tài)分配50MB的內(nèi)存,同時(shí)循環(huán)不退出,這是為了便于觀察系統(tǒng)內(nèi)存的變化。看下圖

注意看Demos.exe*32這個(gè)進(jìn)程,它占用了51,748K內(nèi)存,也就是大約50MB內(nèi)存,換言之分配50MB是成功的。

程序修改為如下形式:

unsigned char *a=new unsigned char[1024*1024*100];
while(true);
 

 

沒錯(cuò)分配了100MB內(nèi)存。下面還有一個(gè)代碼:

while(true)

{

  unsigned char *a=new unsigned char[1024*1024*100];

}

感興趣的可以自己試試,此代碼可以測(cè)試你的系統(tǒng)在幾秒內(nèi)藍(lán)屏。我是不會(huì)測(cè)試這個(gè)代碼的。

這個(gè)代碼會(huì)在循環(huán)中不斷的分配100MB的內(nèi)存,很快內(nèi)存就會(huì)分配完,然后機(jī)器掛掉。

有人也許會(huì)有疑問:a不是一個(gè)局部變量嗎?再次循環(huán)的時(shí)候前一個(gè)a變量不是銷毀了嗎?

的確a會(huì)不斷的產(chǎn)生和銷毀,但那是變量a銷毀。a是一個(gè)指針,a所指的對(duì)象并沒有銷毀。

若要銷毀分配的內(nèi)存可以如下做:

while(true)

{

   unsigned char *a=new unsigned char[1024*1024*100];

   //do something

   delete a[];

}

這個(gè)程序的執(zhí)行結(jié)果如下圖:
時(shí)刻A

 時(shí)刻B

 

時(shí)刻A和B的內(nèi)存是不同的,這說明程序在動(dòng)態(tài)分配內(nèi)存,同時(shí)內(nèi)存不會(huì)一直增加,由于有delete釋放內(nèi)存,因此程序的內(nèi)存在100MB以內(nèi)(為什么是變化的?自己考慮吧)
new和delete比較容易混淆的地方是它們的另外一種用法:
int *a=new int(10);
delete a;
=============
int *a=new int[10];
delete []a;
上述代碼有一個(gè)非常細(xì)微的差別
new int(10);和new int[10];
delete a;和delete []a;
解釋一下
int *a=new int(10);
表示動(dòng)態(tài)分配了1個(gè)int型的內(nèi)存,并將內(nèi)存的值初始化為10,然后將地址賦值給指針變量a。
delete a;
用于刪除指針變量a。
===========================
int *a=new int[10];
表示動(dòng)態(tài)分配了10個(gè)int型的內(nèi)存,并將內(nèi)存的首地址賦值給指針變量a。
delete []a;
用于刪除指針變量a。
============================
換言之
new 類型(參數(shù))用于動(dòng)態(tài)生成單個(gè)變量,并賦初值
delete 變量 用于刪除
new 類型[數(shù)量] 用于分配多個(gè)內(nèi)存空間
delete []變量 用于刪除
 
關(guān)于new和delete另一個(gè)需要記住的地方是new之后必須delete,否則就會(huì)內(nèi)存泄漏。
如果你的程序開始需要new,那么很快你也會(huì)掌握delete。
但如果你的程序從來都不需要new,那么你也不會(huì)明白delete。
如果你的C++程序從來沒有new和delete,那么沒有哪個(gè)公司敢雇用你,除了讓你當(dāng)清潔工。
 
對(duì)比9:名字空間
在C++中如果想使用標(biāo)準(zhǔn)庫中的類和函數(shù)就會(huì)用到名字空間。例如:
#include<iostream>
using namespace std;   //這就是名字空間
int main()
{
    cout<<"hello world"<<endl;
    return 0;
}
其中std是名字空間,using namespace表示使用std這個(gè)名字空間。
關(guān)于名字空間,一般正常的C++書籍都會(huì)介紹,這里就不說了。如果你的C++書籍沒有解釋名字空間,那么建議換一本書(這是有可能的,特別是譚浩強(qiáng)之類的書)。
比較奇怪的一點(diǎn)是,盡管名字空間這個(gè)技術(shù)還算有用,并且標(biāo)準(zhǔn)庫中也用了,但在實(shí)際編程中,大家還很少用 。也許C++程序員現(xiàn)在多數(shù)都是些LIB和DLL,名字沖突的概率比直接寫源碼低的原因吧。
對(duì)比10:inline
一個(gè)函數(shù)用inline修飾就成為內(nèi)聯(lián)函數(shù),如下:
inline void fun()
{
}
inline是給編譯器用的。如果一個(gè)函數(shù)聲明為inline,那么編譯器會(huì)在調(diào)用該函數(shù)的地方直接展開函數(shù)(而不是函數(shù)調(diào)用)。這樣會(huì)增加函數(shù)調(diào)用的效率。內(nèi)聯(lián)函數(shù)可以部分替代C語言的宏定義。
以上只是官方的一種說法。官方其實(shí)還有另外一個(gè)說法,就是inline不是強(qiáng)制性的。換句話說,編譯器可以忽略掉inline。
個(gè)人看法,inline還是不inline真的無法提高什么性能,尤其是如果你想用C++寫面向?qū)ο蟪绦颉?/div>
對(duì)比11:頭文件的使用
C++標(biāo)準(zhǔn)庫的頭文件都是不帶.h結(jié)尾的。例如
#include<iostream>
#include<string>
#include<vector>
事實(shí)上頭文件以.h結(jié)尾只是一個(gè)習(xí)慣,對(duì)于編譯器而言,就算你用.exe結(jié)尾,它也照樣不管。
對(duì)比12:編寫自定義頭文件
如果你沒有編寫過自定義頭文件,那么說明你的程序還不夠大。不夠大的含義是:恐怕不到100行。。。。。
但凡大點(diǎn)的程序都是要寫自定義頭文件的。這有幾個(gè)原因:1.程序分模塊;2.程序分工;3.編譯效率;4.編譯器限制太大的文件。
不詳細(xì)解釋了。自定義頭文件也是項(xiàng)目大到一定程度,自然會(huì)寫的。
關(guān)鍵是怎么寫才正確,這里有幾個(gè)原則。
原則1:只有函數(shù)聲明,不能有函數(shù)實(shí)現(xiàn)
以下代碼稱為函數(shù)聲明
void fun();
以下代碼稱為函數(shù)實(shí)現(xiàn)
void fun()
{
}
那么函數(shù)實(shí)現(xiàn)寫在什么地方呢?寫在一個(gè)cpp文件里面。
至于為什么要這么做,就要扯到編譯器的實(shí)現(xiàn)問題了?傊贿@么做,遲早有一天會(huì)出錯(cuò)。而且錯(cuò)得讓人找不到北。
這里有一個(gè)例外情況inline函數(shù)的實(shí)現(xiàn)是可以放在頭文件里面的。但這只是例外。
原則2:變量聲明加extern
頭文件中聲明的變量一般都是全局變量。如果此變量是常量,那么可以不加extern,其他變量是加上的好。
原因也是編譯器的實(shí)現(xiàn)機(jī)制。
全局變量若定義在頭文件里面應(yīng)該加上extern,如下:
//a.h文件
extern int x;
全局變量的初始化則放到一個(gè)cpp文件中,例如:
//a.cpp
int x=10;
然后在b.cpp文件中就可以使用x了,如下:
#include"a.h"
int main()
{
     x=20;
}
上述代碼如果去掉extern會(huì)出錯(cuò)。
但如果去掉extern,并且把初始化放到頭文件中,則有可能正確。例如
//a.h文件
int x=10;
==========================
#include"a.h"
int main()
{
x=20;
}
這完全可能編譯正確,但也僅僅是由于運(yùn)氣比較好。
如果a.h在多個(gè)cpp文件中被引用就會(huì)出錯(cuò)的。
原則3:用宏定義避免同一個(gè)頭文件被多次#include
//a.h文件
int x=10;
==============================
#include"a.h"
#include"a.h"
int main()
{
x=20;
}
注意a.h被#include了兩次,x就被定義了兩次,不出錯(cuò)才怪呢。
用宏定義就可以避免這種錯(cuò)誤。
//a.h文件
#ifndef A_H
#define A_H
int x=10;
#endif
這樣無論#include幾次,x都只定義1次。
特別注意:如果不采用原則2的寫法,即使加上了宏定義,下列代碼仍然是錯(cuò)誤的。
//b.h
#ifndef B_H
#define B_H
void fun();
#endif
==================
//b.cpp
#include"a.h"
void fun()
{
      x++;
}
===================
#include "a.h"
#include "b.h"
void main()
{
    x++;
}
 
 
 C++的面向過程編程基本上是對(duì)C語言的增強(qiáng),面向?qū)ο蟛攀荂++的核心內(nèi)容。如果你用面向?qū)ο缶幊蹋敲幢疚牡暮芏鄡?nèi)容其實(shí)可以忽略。
寫完了,大家看看有沒有什么遺漏。
 
 
 
 
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 久久久噜噜噜久久中文字幕色伊伊 | 水蜜桃亚洲一二三四在线 | 亚洲一区二区三区四区视频 | 国产精品精品视频一区二区三区 | 成人免费视频网站在线观看 | 91免费观看视频 | 金莲网 | 成人教育av| 黄色网址免费看 | 亚洲午夜av久久乱码 | 国产三级国产精品 | 爱爱视频网 | av国产精品 | 久久99精品国产麻豆婷婷 | 91精品无人区卡一卡二卡三 | 欧美精品在线免费观看 | 午夜欧美 | av大片| 亚洲一区免费视频 | 一级毛片观看 | 欧美成人一区二区三区 | 久草中文在线观看 | 欧美一级特黄aaa大片在线观看 | 97日日碰人人模人人澡分享吧 | 人人擦人人干 | 中文字幕第一页在线 | 色爽女 | 欧美三区在线观看 | 亚洲精品一 | 亚洲va中文字幕 | 国产精品三级久久久久久电影 | 四虎首页| 久久99精品久久久久子伦 | 一区二区三区免费 | 男人的天堂久久 | 成人精品一区亚洲午夜久久久 | 亚洲91| 视频一区二区三区中文字幕 | 九九免费| 久久精品小短片 | 毛片一区 |