c++是在C語言的基礎上發展起來的一門語言,C++是即支持結構化程序編程又支持面向對象程序設計的混合型語言。他一方面提供了對C的兼容性,保持了C的簡介、高效,接近彙編語言的特色,另外一方面,C++引入了類、對象的概念,能夠進行類的繼承和派生,使C++成爲一種面向對象的程序設計語言。早期的具備面向對象性能的程序語言存在不少缺點,如創建對象不凡便,與用戶交互能力差等。C++克服了這些缺點,實現了真正的可視化編程。用戶使用C++時,不用本身一一創建對象,只要在C++提供的框架內添加實現某種功能的代碼便可。ios
c++與C語言兼容,C語言中的數據類型、運算符、表達式、函數定義和調用、預處理命令等在C++中都是適用的,還包括語句格式等。C++繼承了C的風格和特色,但同時又對C的不足和問題作出了改進,主要包括:c++
(1)增長了一些新的運算符,使得C++應用起來更加方便,如::,new,delete,.*,->等。編程
(2)改進了類型系統,增長了安全性。C語言中類型轉換很不嚴格,而C++規定類型轉換大多采用強制轉換,函數的說明必須使用原型,還對默認類型作了限制。數組
(3)增長了「引用」概念,是的引用函數參數更加方便。安全
(4)容許函數重載,容許設置默認參數,這些措施提升了編程的靈活性,還減小了冗餘性。服務器
(5)引進了內聯函數的該概念,提升了程序的效率。框架
(6)對變量說明更加靈活,在知足先定義後使用的前提下,局部變量的定義和聲明能夠在程序塊的任何位置。函數
C++並不是萬能藥,這裏舉出一些C++的適用時機。性能
按應用領域來講,C++適用於開發服務器軟件、桌面應用、遊戲、實時系統、高性優化
用Visual Studio不能單獨編譯一個.cpp或者一個.c文件,這些文件必須依賴於某一個項目,所以必須建立一個新項目,下面建立一個控制他應用程序。
點擊確認後,即進入了以下界面
再輸入程序以下:
1
2
3
4
5
6
7
8
9
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
cout <<
"hello world!\n"
;
return
0;
}
|
#include<iostream>爲預處理命令,預處理器包含在編譯器中。iostream爲C++自帶的庫文件,它包含標準流cin、cout輸入和輸出,當程序中須要用到這些輸入輸出流對象時,要用#include將其包含在程序中。
第二行using namespace std;,該語句是說明程序使用C++標準庫的命名空間std。命名空間是ANSI C++引入的能夠由用戶命名的做用域,用來處理程序中常見的同名衝突。這個再後面會進行講解。
運行程序,能夠獲得以下結果:
·運行結果以下:
C++自己沒有專門的輸入輸出語句,C++的輸出和輸入不是C++自己定義的,而是編譯系統提供的I/O庫中定義的,是用「流」的方式實現的,使用的是iostream庫。
1
|
cout<<表達式1[<<表達式2<<..<<表達式n];
|
該語句功能是:依次輸出表達式一、表達式二、...表達式n的值。具體輸出內容能夠是一個整數、實數、字符及字符串。雖然cout不是C++自己提供的語句,但爲了方便,經常由cout和流插入運算符<<實現輸出的語句稱爲輸出語句或cout語句。下面是一個實例:
1
2
3
4
5
6
7
8
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
cout <<
"this is a c++ program"
<<endl;
}
|
在執行該語句是,系統先把插入的數據順序存放在輸出緩衝中,直到輸出緩衝區滿或遇到cout語句中的endl(或'\n',ends,flush)爲止。將緩衝去中已有的數據一塊兒輸出,並清空緩衝區。
endl表示輸出一個換行字符,同時刷新流,若是不用endl,還可使用轉移字符‘\n'來表示換行。
其中使用cout語句須要注意如下幾點:
例如:cout<<"this is a C++ program"<<endl能夠寫成:
1
2
3
4
|
cout <<
"this "
<<
"a C++"
<<
"program"
<< endl;
|
或者:
1
2
3
4
|
cout <<
"this "
;
cout <<
"a C++"
;
cout <<
"program"
;
cout << endl;
|
cin語句通常格式
1
|
cin>>變量>>[變量>>...>>變量n];
|
該語句功能爲:運行程序時從鍵盤輸入變量一、變量二、...變量n的值。
使用該語句須要注意如下幾點:
運行程序是,從鍵盤上輸入多個變量,多個值之間用空格、Tab或回車鍵分開。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// example1.cpp: 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
char
c1, c2;
int
a;
float
b;
cin >> c1 >> c2 >> a >> b;
}
|
須要注意的是不能用cin語句把空格字符和回車換行符做爲字符輸入給字符變量,他們將被跳過。若是想將空格字符或者回車換行符輸入給字符變量,可使用getchar()函數。
利用格式控制符能夠進行格式化的輸入和輸出。用oct、dec、hex分別將輸入或輸出的數值換成8進制、10進制及16進制。例如:
1
2
3
|
cout << oct << a << endl;
//輸出a的8進制
cout << dec << a << endl;
//輸出a的10進制
cout << hex << a << endl;
//輸出a的16進制
|
此外,還有不少格式控制符,例如:
ws:輸入流的時候刪掉空白字符。
ends:輸出一個null字符。
endl:輸出一個換行字符,同時刷新流。
flush:刷新流。
下面經過一個實例加深瞭解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// example1.cpp: 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
char
a[20];
cin >> a;
cout << a << endl;
return
0;
}
|
這裏發現,輸入aaa bbb輸出卻只爲aaa,這是由於碰見空格後就結束了,後面BB沒法讀取出來,因此輸出的是aaa.
變量的做用與即變量的做用範圍。有的變量能夠在整個程序或其餘程序中使用,有的則只能在局部範圍內使用。按做用域範圍範圍能夠將變量分爲兩種:局部變量和全局變量。
變量的生存期是指變量從生成到被撤銷的這段時間。實際上就是變量佔用內存的時間。按生存期長短可將變量分爲兩種:動態變量和靜態變量。
變量只能在其生存期裏被引用,變量的做用域直接影響變量的生存期。做用域和生存期是從空間和時間的兩個不一樣的角度來描述變量的特性。
在一個函數內部定義的變量就是局部變量,其做用域只在本函數範圍內有效,也就是說只有在本函數內才能使用他們,在此函數以外是不能使用這些變量的,這是由於函數內的變量是保存在棧內的,而全部棧內的內容在函數調用結束後會被清除。因此,局部變量的生存期是從函數被調用的時刻開始到函數返回調用處的時刻(靜態變量除外)結束。在使用局部變量時,須要注意如下幾點:
int max(int a, int b);//函數聲明a、b int max(int x, int y)//函數定義,形參是x、y { cout << x << y << endl;//合法,x、y在函數內有效 cout << a << b << endl;//非法,a、b在函數體中無效。 }
編譯時,系統認爲函數體中的a\b未經定義。
2.全局變量做用域和生存期
在函數外部作定義說明的變量,稱爲外部變量。它屬於整個源程序文件。這是由於全局變量是保存在堆中的,堆內的數據能夠從程序開始運行一直到程序運行結束。其做用域從定義變量的未知開始到源文件結束,或者是有extern說明的其餘源文件。全局變量的生存期和程序相同。使用時須要注意如下幾點:
1
|
[
extern
] 類型說明符全局變量名1[ =初始值1],...,全局變量名n[ =初始值n];
|
extern 類型說明符 全局變量名1,...,全局變量名n;
在C++中變量除了有數據類型的屬性以外,還有存儲類別的屬性。存儲類別指的是數據在內存中的存儲方法。存儲方法分爲靜態存儲和動態存儲兩大類。具體包含四種:自動(auto)、靜態的(static)、寄存器的(register)和外部的(extern)。
考慮了變量的存儲類型後,變量定義的完整形式應爲:
1
2
3
4
5
6
|
存儲類型說明符 數據類型說明符 變量名1,變量名2,...變量名n;
例如:
auto
char
c1,c2;
register
i;
static
int
a,b;
extern
int
x,y;
|
程序中大多數變量屬於自動變量。函數中的局部變量,若是不用關鍵字static加以聲明,編譯系統對它們是動態的分配存儲空間的。函數的形參和在函數中定義的變量(包括在符合語句中定義的變量)都屬於此類。在調用該函數時,系統給形參和函數中定義的變量分配存儲空間,數據存儲在動態存儲區中,在函數調用結束後自動釋放這些空間。若是是在複合語句中定義的變量,則在變量定義時分配存儲空間,在符合語句結束時自動釋放空間。若是在符合語句中定義的變量,則在變量定義時分配存儲空間,在複合語句結束時自動釋放空間。所以者類局部變量稱爲自動變量。自動變量用關鍵字auto做存儲類別的聲明。
例:
1
2
3
4
|
int
f(
int
a)
//定義f函數,a爲形參
{
auto
int
b, c = 3;
//定義b和c爲整型的自動變量
}
|
存儲類型auto與int的順序是任意的,並且關鍵字auto還能夠省略,若是不寫auto,則系統默認爲自動存儲模式,它屬於動態存儲方式。
注意,用auto、register、static聲明變量時,是在定義的基礎上加上這些關鍵字,而布恩那個單獨使用。
2.靜態變量
靜態變量在整個程序生命週期內,其地址靜止不變。
靜態變量的類型說明符是static。靜態變量屬於靜態存儲類型,但靜態存儲類型的變量不必定是靜態變量。例如,外部變量雖屬於靜態存儲類型,但不必定是靜態變量,必須用static加以定義後才能稱爲靜態外部變量。
全局變量改變爲靜態變量後會改變它的做用域,限制了它的使用範圍。當一個源程序由多個源文件組成時,非靜態的全局變量可經過外部變量說明使其在多個文件中都有效。而靜態全局變量只在定義該變量的源文件內有效,在同一項目的其餘源文件中不能使用。
自動變量能夠用static改變爲靜態自動變量,改變後,其生存週期爲整個源程序,可是做用域與自動變量相同。此外須要注意的是,靜態局部變量賦字操做只運行一次,此後再調用,再也不進行賦值。
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
int
i;
void
func();
//函數說明
for
(i = 1; i <= 5; i++)
func();
//函數調用
return
0;
}
void
func()
//函數定義
{
static
int
j = 1;
//靜態局部變量,其只運行一次。
++j;
cout << j <<
""
;
}
|
能夠看到,五次調用函數func,可是賦值給j=1的操做只執行了一次。
3.寄存器變量(register型變量)
通常狀況下,變量的值是存放再內存中的,當程序中用到哪個變量的值時,由控制器發出指令將內存中該變量的值送到CPU的運算器中,而寄存器變量存放在CPU的寄存器中,使用時,不須要訪問內存,而是直接從寄存器中讀寫,這樣可提升效率。
寄存器變量的說明符爲register,屬於動態存儲類型。只有局部自動變量和形式參數才能夠定義爲寄存器變量。
4.外部變量
外部變量(即全局變量)是在函數的外部定義的,它的做用域爲從變量的定義開始,到本程序文件的末尾。在此做用域內,本文件的各個函數均可以引用全局變量。編譯時將全局變量分配到靜態存儲區。
若是外部變量不在文件的開頭定義,其有效的做用範圍只限於定義處到文件結束。若是在定義以前想引用該全局變量,則應該在引用以前用關鍵字extern對該變量作外部變量聲明,表示該變量是一個在後面定義的全局變量。有了此聲明,就能夠從聲明處起,合法的引用該全局變量,這種聲明稱爲提早引用聲明。若是程序由多個文件組成,在一個文件中定義的外部變量,在另外一個文件中對該外部變量進行聲明後,也能夠合法的引用該外部變量。
用extern擴展全局變量的做用域,雖然給程序帶來了方便,但會使程序的可讀性變差,修改不便,使用時要慎重。
在C和C++中使用函數時,包括函數的聲明、定義、調用三部分,都要遵照相應的規則。
函數聲明就是把函數的名字、函數類型以及形參的個數、類型和順序通知編譯系統,以便在遇到函數調用時,覈查調用形式是否與聲明相符。
函數聲明的通常形式:
1
2
3
|
函數類型 函數名(參數類型1 參數名1,參數類型2 參數名2,...);
函數類型 函數名(參數類型1,參數類型2..);
|
第二種聲明是對第一種聲明的簡化,它省略了參數名,由於函數聲明不涉及函數體,因此編譯系統不關心參數是什麼。
函數定義是指對函數功能的實現,包括指定函數名、函數類型、形參及其類型、函數體等,他是一個完整的、獨立的函數單位。
函數定義的通常形式:
1
2
3
4
5
6
|
函數類型 函數名(形式參數表)
{
聲明部分;
函數體主體;
return
返回值;
}
|
使用該函數,叫作函數調用,函數調用方式是:
1
|
函數名(實際參數表)
|
只要函數聲明出如今函數調用以前,就能夠把包含函數體的函數定義移到函數調用的後面。所以,在程序中調用函數由如下兩種方式:
1
2
3
4
5
6
7
8
|
方式1:
函數聲明;
函數調用;
函數定義;
方式2
函數定義;
函數調用;
|
例如以前的例子,還能夠這樣寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
void
func()
//函數定義
{
static
int
j = 1;
//靜態局部變量,其只運行一次。
++j;
cout << j <<
""
;
}
int
main()
{
int
i;
for
(i = 1; i <= 5; i++)
func();
//函數調用
return
0;
}
|
C++容許給函數形參賦予默認值。所謂默認值就是在調用時,能夠沒必要給出某些參數的值,編譯器會自動把默認值傳遞給調用語句。對於函數的形參,能夠給出默認值,也能夠不提供默認值,還能夠指對形參的一部分給出默認值。默認值在函數參數較多時是很是有用的。能夠只傳必需的值。
使用默認參數時,須要注意如下幾點:
參數的默認值能夠在聲明中或定義中設置,但只能在其中一處設置,不容許在兩處同時設置。若是函數的定義在函數調用以後,則只能在函數聲明中設置默認參數。由於此時若是在定義中設置,編譯器不知道哪一個參數設置了默認值。
設置了默認值的參數,函數調用是能夠再也不給值,直接讀取默認值,也能夠不區默認值,從新賦值。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
add(
int
a,
int
b = 5);
//函數聲明
int
main()
{
int
a = 1;
int
b = 2;
cout<<add(a, b) << endl;
//函數調用,第二個參數沒有取默認值
cout << add(a) << endl;
//函數調用,第二個參數取默認值
return
0;
}
int
add(
int
x,
int
y)
//函數定義
{
int
z;
z = x + y;
return
z;
}
|
輸出結果爲:
若是一個函數中有多個默認參數,則默認參數應從右到左逐漸定義。即當某個參數是默認參數,那麼它後面的參數必須都是默認參數。例如:
1
2
3
|
int
add(
int
a,
int
b,
int
c=1);
//true
int
add(
int
a=1,
int
b=1,
int
c=1);
//true
int
add(
int
a=1,
int
b=1,
int
c);
//false
|
當調用函數時 ,傳進去的實參個數必須大於或等於無默認值的形參的個數,匹配參數時是從左至右去匹配。例如,對三個參數都是默認參數的,正確的調用格式爲:
1
2
3
|
add()
//三個參數都取默認值1,函數值爲3
add(2,3)
//a=2,b=3,c取默認值1,函數值爲6
add(3,4,5)
//a、b、c都不取默認值,結果爲12
|
在前面的例子中,參數默認值都是常量,實際上,默認值能夠是全局變量,甚至是一個函數調用。
例如
1
2
3
|
int
m = 1;
//m爲全局變量
int
fun(
int
i = m);
//正確,參數默認值爲全局變量m
int
add(
int
x;
int
y = fun());
//正確,add函數的參數默認值爲fun()函數值,並且,fun()函數調用使用的是參數默認值。
|
但默認值不能是局部變量,由於默認參數的函數調用是在編譯時肯定的。
函數編程過程當中,常常會遇到這種狀況,就是須要編寫若干個函數,他們的功能類似,可是參數不一樣,能夠統一給這些函數取一個相同的名字,但設置不一樣的參數,編譯系統在函數調用時可以將各個函數區分開來。若是兩個函數名字相同而且在相同的域中被聲明,可是參數表不一樣,那麼他們就是重載函數。
重載函數必須是參數類型或參數個數不一樣。使用重載函數須要注意:
函數重載要求編譯器可以惟一的肯定調用一個函數應執行哪一個函數代碼,即採用哪一個函數實現。進行函數重載時,要求同名函數在參數個數上不一樣,或者參數類型上不一樣,不然,將沒法進行重載。
例:編寫兩個重載求和函數,一個計算兩個整數的和,一個計算兩個浮點型數的和。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
add(
int
x,
int
y);
//函數聲明
double
add(
double
a,
double
b);
int
main()
{
cout<<add(2, 3) << endl;
//函數調用,第二個參數沒有取默認值
cout << add(2.2,3.3) << endl;
//函數調用,第二個參數取默認值
return
0;
}
int
add(
int
x,
int
y)
//函數定義
{
return
x + y;
}
double
add(
double
a,
double
b)
//函數定義
{
return
a + b;
}
|
內聯函數是C++引進的新概念,在C語言中沒有。內聯函數具備通常函數的特性,他與通常函數的不一樣之處只在於函數調用的處理。通常函數進行調用時,要將程序執行權轉到被調用函數中,執行完被調用函數後纔再次返回到調用它的函數中;而內聯函數是在編譯時直接將內聯函數的函數體代碼嵌入到調用函數中,因此內聯函數被執行時,不涉及到流程的轉出和返回,也不涉及到參數傳遞,提升了執行效率。
內聯函數是在函數聲明或函數定義是,在函數名前加一個inline。示例以下
1
2
3
4
|
inline
int
add(
int
x,
int
y)
//函數定義
{
return
x + y;
}
|
使用內聯函數有如下注意事項:
引用是C++中提供的一個新概念,它與指針密切相關。引用是一個變量的別名,定義引用類型變量,實質上是給一個已定義的變量起一個別名,系統不會爲引用類型變量分配內存空間,只是使引用類型變量和其相關聯的變量使用同一個內存空間。
定義引用類型變量的通常格式爲:
1
2
3
4
5
|
<數據類型> &<引用名>=<變量名>
//&不是取地址符,是引用的標識
或
<數據類型> &<引用名> (變量名)
|
例如:
1
2
|
int
a=3;
int
&ra = a;
|
這裏,ra就是一個引用,他是變量a的別名。引用ra和變量a不只值相同,地址也相同。對引用進行的計算,例如:ra=ra+2;實質上是a加上2,a的結果爲5.
使用引用的注意事項以下:
下面經過一個實例加深瞭解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include "stdafx.h"
#include "iostream"
using
namespace
std;
int
main()
{
int
a;
int
&ra = a;
//將ra引用爲a
cout <<
"a="
<< a << endl;
cout <<
"ra="
<< ra << endl;
cout <<
"address of a is :"
<< &a << endl;
cout <<
"address of ra is :"
<< &ra << endl;
int
b = 8;
ra = b;
cout <<
"a="
<< a << endl;
cout <<
"b="
<< b << endl;
cout <<
"ra="
<< ra << endl;
cout <<
"address of a is :"
<< &a << endl;
cout <<
"address of b is :"
<< &b << endl;
cout <<
"address of ra is :"
<< &ra << endl;
return
0;
}
|
運行結果:
引用傳遞是指將引用做爲函數參數來實現的函數參數的傳遞。
通常的,函數形參爲通常變量,調用時實參與形參之間參數傳遞只能是從實參到形參,是單向的。從被調用函數的角度來講,參數的值只能傳入,不能傳出,也就是一般的值傳遞。當用指針做爲函數參數,調用時將實參的地址初始化成形參的指針,則能夠實現實參和形參的雙向傳遞,即地址傳遞。
引用傳遞是指引用做爲函數的形參,當調用函數是,對應的形參就是相應實參的別名。在調用函數內對形參的修改就是對實參的修改;在調用函數外對實參的修改,當進入被調用函數內時,相應的形參就是已經修改的實參,實現了參數的雙向傳遞。
例:利用自定義函數交換兩個變量的值,要求用引用做爲函數形參。
下面程序中自定義函數的形參爲引用。