C++程序設計
之前學過C++課程,但是時間有點久,忘了很多,這裏做一個簡單的回顧。
網站推薦: C++在線編譯器
學習C++之前,您可以先了解C語言。
c++的擴展名一般爲cpp(cplusplus)。
補充: 這裏介紹瞭如何編譯和執行C++文件,即一般需要下面的步驟:
在文件的外面shift + 右鍵單擊,選擇cmd打開文件(cpp的外層文件)
g++ 文件名.cpp -o test
test
通過這三步就可以編譯C++文件了。
注意:1. 每次如果修改了文件,都需要在g++ 文件名.cpp -o test來重新編譯文件得到文件名.exe可執行文件,然後在執行即可。這時新的可執行文件就可以覆蓋舊的可執行文件。
2. 在notepad++中的設置-> 語言設置中將語言設置爲C++
第一部分: 面向對象程序設計概述
1 面向過程的程序設計和麪向對象的程序設計
面向對象程序設計與面向過程程序設計有着本質的區別。
面向過程程序設計是以功能爲中心,數據和操作數據的函數(或過程)相分離,程序的基本構成單位是函數。
而面向對象程序設計是以數據爲中心,數據和操作數據的函數被封裝成一個對象,與外界向分隔,對象之間通過消息進行通信,使得各對象完成相應的操作,程序的基本構成單位是對象。
簡單地說,面向過程的程序設計是以函數爲基本構成單位; 而面向對象的程序設計是以對象爲基本構成單位。
2. 爲什麼C++是面向對象的程序設計? 面向過程的程序設計有什麼不足呢?
面向過程的程序設計是圍繞功能進行的,用一個函數實現一個功能。 所有的數據都是公用的,一個函數可以使用任何一組數據,而一組數據又可以被多個函數所使用。 當程序規模較大時、數據很多時,程序設計者往往感到難以應付。 所以面向過程的程序設計往往只適用於規模較小的程序。
面向過程的程序設計其數據是公有的,誰也沒有辦法限制其他的程序員不去修改全局數據,也不能限制其他程序員在函數中定義與全局數據同名的全局變量,故很不安全。
由於面向過程程序設計的基本單位是函數,所以代碼重用的最大粒度就是函數,對於今天的軟件開發來說,程序修改的難度很大。
基於以上面向過程的程序設計的不足,人們提出了面向對象的程序設計。
3. 面向對象的編程思想
(1)客觀世界中的事物都是對象(object),對象之間存在一定的關係。
(2)用對象的屬性(attribute)描述事物的靜態特徵,用對象的操作(operation)描述事物的行爲(動態特徵)。
(3)把對象的屬性和操作結爲一體,形成一個相對獨立、不可分的實體。對象對外屏蔽其內部細節,只留下少量接口,以便和外界聯繫。
(4)通過抽象對對象進行分類,把具有相同屬性和相同操作的對象歸爲一類,類是這些對象的描述,每個對象是其所屬類的一個實例。
(5)複雜的對象可以使用簡單的對象作爲其構成部分。
(6)通過在不成程度上運用抽象的原則,可以得到一般類和特殊類。特殊類可以繼承一般類的屬性和操作,從而簡化系統的構造過程。
(7)對象之間通過傳遞消息進行通信,以實現對象之間的動態聯繫。
(8)通過關聯表達類之間的靜態關係。
4. 面向對象的基本概念
1. 對象
從現實角度來說, 現實世界中的任何一個事物都可以看做一個對象,如汽車、房屋等,這些都是有形的;又如文章、計劃等,這些都是無形的。對象有大有小,如一個軍隊是一個對象,一個螞蟻也是一個對象。
任何一個對象都具有兩個基本要素:屬性和行爲。屬性是用來描述對象的靜態特徵。行爲是用來描述事物的動態特徵。 如一個人是一個對象,其身高、性別就可以看做屬性,其可以走路、說話、打球就可以看做其行爲。
且在對象之間一定要有聯繫,如電視這個對象被人這個對象按了一下開機按鈕, 電視這個對象就開機了,這就是對象與對象之間的聯繫。
總結:對象具有表示靜態特徵的屬性和表示動態特徵的行爲,對象與對象之間需要傳遞信息來聯繫。
2. 類
類是對客觀世界中具有相同屬性和行爲的一組對象的抽象,它爲屬於該類的全部對象提供了統一的對象描述,其內容同樣包括對象和屬性。
那麼什麼是抽象呢? 抽象就是指忽略事物的非本質特徵,只注意那些和當前目標有關的本質特徵,從而找出事物的共性。比如人就可以看做一個類,即人類,其中他是世界上所有實體人如張三、李四、王五的抽象。
總結:類是對象的抽象,而對象則是類的實例,或者說是類的具體表現形式。
3. 封裝
日常生活中的封裝很多,如錄像機,從外面來看他就是一個黑盒子,在他的表面有幾個按鍵,而其內部的電路板和機械控制部件在外面是看不到的。
這樣做的好處在於大大降低了人們操作對象的複雜程度,使用對象的人完全不需要知道對象內部的具體細節,只需要瞭解其外部功能即可自如地操作對象。
在面向對象方法中,所謂“封裝”即包括兩方面的含義:(1)用對象把屬性和操縱這些屬性的操作保證起來,形成一個基本單位,各個對象之間相互獨立,互不干擾; (2)將對象中某些部分對外影藏,即影藏其內部細節,只留下少量的接口,以便於和外部聯繫,接受外界的消息。
4. 繼承
所謂繼承是特殊類自動地擁有或者是隱含地複製其一般類的全部屬性和操作。
集繼承具有‘是一種’的含義,如卡車“是一種”汽車,“轎車”是一種汽車,二者作爲特殊類繼承了一般類 --汽車類的所有的屬性和操作。
我們也可以一個特殊類繼承多個一般類,這就是多繼承的概念。如繼承了“銷售”類和“經理”類就是“銷售經理”。
C++提供的繼承機制,就可以很方便的在一個已有的類的基礎上建立一個新類,這就是常說的“軟件重用”的思想。
5. 消息
對象之間通過消息進行通信,實現了對象之間的動態聯繫。 在C++中,消息就是函數調用。
6. 關聯
關聯是兩個多多個類之間的一種靜態關係。 如一個教室類可以管理一個學生類
7. 組合
組合描述的類和類之間的整體和部分之間的關係。如汽車和發動機之間的關係就是組合。 其實,組合是關聯的一種。
8. 多態性
如某個董事長出差,他把這個消息告訴了身邊的人: 妻子、司機、祕書。 這些人聽到之後會有不同的反應:他的妻子給他準備行李、祕書爲他確認考察地安排住宿、司機會爲他準備車輛。 這就是多態。
在面向對象方法中,所謂多態性是指由繼承而產生的相關而不同的類,其對象對同一個消息會做出不同的響應。
第二部分:基礎知識
1. C++是什麼?
C++ 是一種靜態類型的、編譯式的、通用的、大小寫敏感的、不規則的編程語言,支持過程化編程、面向對象編程和泛型編程。
C++ 被認爲是一種中級語言,它綜合了高級語言和低級語言的特點。
C++ 是由 Bjarne Stroustrup 於 1979 年在新澤西州美利山貝爾實驗室開始設計開發的。C++ 進一步擴充和完善了 C 語言,最初命名爲帶類的C,後來在 1983 年更名爲 C++。
C++ 是 C 的一個超集,事實上,任何合法的 C 程序都是合法的 C++ 程序。
注意:使用靜態類型的編程語言是在編譯時執行類型檢查,而不是在運行時執行類型檢查。
2. 基本結構
#include <iostream> std; // main main () { cout << ; ; }
C++定義了一些有用的頭文件,我們必須引入<iostream>, 否則類似cout和cin 的輸入輸出都是不可用的。
using namespace std;這是一個語句,所以一定要用分號結尾。 這是C++中的命名空間,js中是沒有的。
// main 其中// 表示單行註釋,這裏所在的語句表示程序開始的地方,我們寫代碼一般都是要在這裏寫的。
下一行 int main() 是主函數,程序從這裏開始執行。
cout一定要和<<配合使用,指的是輸出。
return 0; 表示終止函數,在C++中一般都是這樣來寫的。當然, return 8; return 45;什麼的都是可以的。
注意:C++中和js一樣,都是使用;分號來表示語句的結束,但是和js不同的是,js某些情況下可以省略,但是C++中永遠都不可以。
注意:我們也可以不適用 using namespace std; 但是在程序中我們如果要使用cin和cout就必須在其前面添加 std::如下所示:
#include <iostream>int main() { static int zhu = 15; std::cout << zhu ; }
最終會輸出 15
3. C++中的標識符
在C++中,可以使用字母、下劃線作爲首字母,而後可以跟字母、下劃線和數字。 注意:c++中是不支持$的,這點需要格外注意。 且C++是區分大小寫的。
4. 和js一樣,C++中也有一些保留字,我們再給變量命名的時候,是不能使用的。
5. C++中的數據類型有哪些?
bool 布爾型
char 字符型
int 整型
float 浮點型
double 雙浮點型
void 無類型
wchar_t 寬字符型
上面是七種基本類型,每一種基本類型還可以使用一個多多個類型修飾符進行修飾。類型修飾符如下:
short
long
signed
unsigned
不同的類型所佔的內存是不同的,我們可以使用sizeof()方法來輸出,如下所示:
#include <iostream>using namespace std;int main() { cout << sizeof(int) << endl << sizeof(char) << endl << sizeof(bool) << endl << sizeof(double); return 0; }
如上面的代碼會得到 4 1 1 8,可以看出double所佔的字節數是最多的。
http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/23/2652696.html C++中的四種類型轉化方式。
6. typedef
C++中typedef 的作用是將一個已有的類型的名稱修改,def即定義的意思,如下所示:
typedef int zhu; zhu vari;
那麼這時的vari就是整型變量。
7. 變量的聲明和初始化
int a;
bool b;
char c;
上述都是變量的聲明。我們還可以在聲明的同時初始化。
int a = 15;
bool b = true;
char c = "good";
int e = 15, f = 45;
我們還可以看到,我們可以一次聲明並且初始化多個變量。
注意: 變量的初始化是一個好習慣,我們最好每次再定義變量的時候都要初始化;
看下面的例子:
#include <iostream>using namespace std; int main () { int zhu = 20; cout << zhu << endl ; return 0; }
最終會輸出20。
我們再看一個函數調用的例子。
#include <iostream>using namespace std;int add();int main () { add(); return 0; }int add() { int zhu = 10; cout << zhu; }
最終會輸出20.
注意:
函數如何要調用,就一定要先聲明,如 int add(); 或者之間在前面定義好。
另外可以看到C++中定義函數直接使用 int 變量名(); 即比一般的變量多了一個()即可。 且由於C++是自上而下執行的,所以我們必須提前聲明,這樣,會自動找到處於下方的函數定義。
8. c++中的變量
一般,在c++中可以有三個地方聲明變量,一個是 代碼塊內部聲明變量,此即局部變量。 還可以在函數的參數中聲明變量,這是形式參數。 也可以在函數外面聲明變量,這是全局變量。
其中局部變量只能在代碼塊中使用,全局變量可以在函數內也可以在函數外,即全局變量一旦聲明,在整個程序中都是可用的。且和js一樣,可以在代碼塊中聲明和全局變量相同的名字,只是在代碼塊中使用會覆蓋全局變量。
如下:
#include <iostream>using namespace std; // 全局變量聲明int g = 20; int main () { // 局部變量聲明 int g = 10; cout << g; return 0; }
最後輸出的是 10。
9. 定義常量
在C++中,定義常量有兩種方式,一種是使用 #define 常量名 常量值 顯然使用這種方式常量值的類型是不確定的。 還有一種可以確定常量值的類型的,就是使用 const 類型 變量名 = 變量值; 舉例如下:
#include <iostream>using namespace std;#define zhu 100int main() { const int he = 99; cout << zhu << endl << he; }
此代碼最終就會輸出 100 99。
10. C++存儲類
C++中的存儲類用於定義其變量(函數)的聲明週期和範圍(可見性)。下面主要介紹幾種:
自 C++ 11 以來,auto 關鍵字用於兩種情況:聲明變量時根據初始化表達式自動推斷該變量的類型、聲明函數時函數返回值的佔位符。 這種方式似乎和js中的var是一樣的,我們看看下面的例子:
#include <iostream>using namespace std;int main() { auto zhu = 15; auto z = 'h'; cout << zhu << endl << z; }
最終輸出 15(int類型)和 h(字符)
register 存儲類用於定義存儲在寄存器中而不是 RAM 中的局部變量。這意味着變量的最大尺寸等於寄存器的大小(通常是一個詞),且不能對它應用一元的 '&' 運算符(因爲它沒有內存位置)。使用register要聲明類型,如下:
#include <iostream>using namespace std;int main() { register int zhu = 15; cout << zhu ; }
static我們知道一般情況下全局變量會始終存在,但是局部變量一旦被調用過後就會被銷燬。但是如果我們使用 static 關鍵字。那麼這個變量即使是局部變量也可以恆久存在,也就是說 static既可以用在局部變量也可以用在全局變量上。
#include <iostream>using namespace std;int main() { static int zhu = 15; cout << zhu ; }
最終會輸出 15
11. C++中的運算符
在C++中,和其他語言一樣,都有自己的運算符,如 + - / * 等等,指的注意的是,判斷是否相等,使用 == 即可,不像js中使用 === 的情況。
想要了解更多,點擊這裏。
12. C++函數
什麼是函數? 函數就是很多語句組合在一起可以做某一件事情的東西。 這就是函數。每個 C++ 程序都至少有一個函數,即主函數 main() ,所有簡單的程序都可以定義其他額外的函數。
另外:C++標準庫還提供了大量的我們可以直接使用的內置函數, 如 strcat()用於拼接兩個字符串等等。
和js的函數不同的是,C++的函數直接使用 int 即可,當然最後在函數內部你也要返回相應的int值,如return 0; 另外就是在傳遞參數的時候要使用 int類似的類型確定其類型,舉例如下:
int max(int num1, int num2) { // 局部變量聲明 int result; if (num1 > num2) result = num1; else result = num2; return result; }
這就是一個很常見的函數了, int確定函數的類型, max爲函數名,我們調用函數的時候就使用該函數名。 傳入兩個參數,必須使用 類型聲明。 最後返回一個int類型的值。
當然這個是函數定義,我們也可以在前面先聲明,即 int max(int, int); 可以發現這裏省略了 num1和num2,因爲這些都是不重要的, 類型正確即可。
13. 函數參數
c++中的函數參數是形式參數,其和函數內的其他局部變量實際上是一樣的。即在進入時被創建, 執行結束被銷燬。
如下所示:
即一般情況下我們使用的是傳值調用,即這是把實際值複製給了函數的形式參數,所以,在這種情況下,修改函數內部的形式參數對實際值沒有影響。
#include <iostream>using namespace std;int a = 15;int b = 20;int modify(int, int);int main() { modify(a, b); cout << "主函數的a:" <<a << endl << "主函數的b:" << b; }int modify(int a, int b) { a = a + 85; b = b + 20; cout << "函數內部的a:" <<a << endl << "函數內部的b:" << b << endl ; }
結果如下:
函數內部的a:100函數內部的b:40主函數的a:15主函數的b:20
可以看到: 在函數內部修改了傳進來的參數,只是修改了clone版本,並沒有修改真正的a和b。 這也就是傳值調用。
在C++的函數中,我們也可以使用 參數的默認值,即如果傳入了該參數,那麼就是用; 如果沒有傳入,就是用默認值,如下所示:
int sum(int a, int b=20) { int result; result = a + b; return (result); }
14. C++中的數字運算
我們可以引入 cmath庫,然後使用C++自帶的數字運算的函數,舉例如下:
#include <iostream> #include <cmath>using namespace std;int main() {int a = -10;double b = 4.54;float c = 45.2; cout << abs(a) << endl << sqrt(b) <<endl << pow(c, 2); }
注意:這裏必須引用 cmath庫,即 #include <cmath> 然後就可以使用諸如 sqrt() abs() pow() floor() sin() cos() tan()之類的函數了。
15. 數組
在C++中聲明數組的方法很簡單,即:
int numbers[10];
其中int也可以換成其他你需要的類型,如 double等 。 在變量名後面的數字一定要大於0,這裏爲10表示這個數組中可以放下長度爲10的數。
我們還可以初始化數組,只是這裏初始化數組使用的是{},在數組的定義和初始化方面C++和js的差別較大。如下所示:
#include <iostream>
using namespace std;
int main()
{
int numbers[8] = {45, 12, 85, 56};
cout << numbers[0] << endl<< numbers[1] << endl<< numbers[2] << endl<< numbers[3] << endl;}
最終的輸出結果: 45, 12, 85, 56
我們也可以不限制數組的長度: 如 int numbers[] = {45, 12, 85, 56};
16. C++字符串
在C++中,由於字符串的特殊性,一般情況下,我們是需要單獨來將字符串的。在C++中有兩種方式表示,一種是引入的C語言風格的,另一種是C++特有的。
char str[] = {'h', 'e', 'l', 'l','o', '\0'};
字符串實際上是使用 null 字符 '\0' 終止的一維字符數組。因此,一個以 null 結尾的字符串,包含了組成字符串的字符。 可以看出,這裏字符串的寫法與數組非常相似。
還可以寫成下面這種形式:
char str[] = "hello";
上面兩種方式的字符串的效果是一樣的。
最終的存儲形式就是這樣,最後一位是使用null佔位表示結束。
在C++中,有大量的處理字符串的內置函數,如果希望使用這樣函數,需要引入cstring(正如數學運算引入了cmath一樣)舉例如下所示:
#include <iostream> #include <cstring>using namespace std;int main() { char str1[] = "zhuzhenwei"; char str2[] = "hetingting"; cout << strlen(str1) << endl << strlen(str2) << endl; cout << strcat(str1, str2) << endl; }
最終輸出:10 10 zhuzhenweihetingting
上面所說的都是C語言中字符串的實現,下面的是C++的。
C++ 標準庫提供了 string 類類型,支持上述所有的操作,另外還增加了其他更多的功能。
看下面的例子:
#include <iostream> #include <string>using namespace std;int main () { string str1 = "Hello"; string str2 = "World"; string str3; int len ; // 複製 str1 到 str3 str3 = str1; cout << "str3 : " << str3 << endl; // 連接 str1 和 str2 str3 = str1 + str2; cout << "str1 + str2 : " << str3 << endl; // 連接後,str3 的總長度 len = str3.size(); cout << "str3.size() : " << len << endl; return 0; }
值得注意的是: 這裏引入的是:#include <string> 而不再是 #include <cstring>, 兩者的區別在哪呢?
顯然,cstring是c語言中的string,而string就是C++中類string,所以這裏我們用到了鏈式調用,可以看出面向對象的C++使用起來多麼方便,如果js也可以這樣隨便引入,就太好了。
17. C++指針
C++中比較有特色的當然就是指針了。這也是我複習C++的一個理由~ 看完這個就要睡覺啦~ 好睏啊
哈哈,讓我們先來看一看教程的說法:
學習 C++ 的指針既簡單又有趣。通過指針,可以簡化一些 C++ 編程任務的執行,還有一些任務,如動態內存分配,沒有指針是無法執行的。所以,想要成爲一名優秀的 C++ 程序員,學習指針是很有必要的。
恩,加油吧,撿起來這一部分內容,先看看下面的代碼:
#include <iostream>using namespace std;int main () { int var1; char var2[10]; cout << "var1 變量的地址: "; cout << &var1 << endl; cout << "var2 變量的地址: "; cout << &var2 << endl; return 0; }
這和之前的有什麼區別的? 恩,就是多了個&, 這在C++中是用來取地址的,即你這個變量住在哪?(變量的內存地址) 看看輸出的結果:
var1 變量的地址: 0x7fff9d7403ec
var2 變量的地址: 0x7fff9d7403f0
0X是指16進制的數字。
那麼什麼是指針呢?
指針是一個變量,其值爲另一個變量的地址,即,內存位置的直接地址。聲明指針的方式如下:
type *name;
如 int *p; 這裏就聲明瞭一個p指針,注意:這裏帶有*, 是說我聲明瞭一個指針,但是並不是說*p是指針,因爲p纔是真正的指針,而*p是指這個p指針所指向地址的值。 *和指針是密切相關的。如下面的聲明方式都是有效的指針聲明:
int *ip; /* 一個整型的指針 */double *dp; /* 一個 double 型的指針 */float *fp; /* 一個浮點型的指針 */char *ch /* 一個字符型的指針 */
看看這個在C++中使用指針的例子:
#include <iostream> using namespace std;int main () { int var = 20; // 實際變量的聲明 int *ip; // 指針變量的聲明 ip = &var; // 在指針變量中存儲 var 的地址,因爲指針的值是地址!!!!!!!!!! 而&var 就是在取變量var 的地址。 cout << "Value of var variable: "; cout << var << endl; // 輸出在指針變量中存儲的地址 cout << "Address stored in ip variable: "; cout << ip << endl; // 訪問指針中地址的值 cout << "Value of *ip variable: "; cout << *ip << endl; // 這裏ip是指針,它的值就是地址,而*ip是地址所在的值,故最終是20 return 0; }
結果如下:
Value of var variable: 20
Address stored in ip variable: 0x7fff99a46294
Value of *ip variable: 20
18. C++引用
引用變量是一個別名,也就是說,它是某個已存在變量的另一個名字。一旦把引用初始化爲某個變量,就可以使用該引用名稱或變量名稱來指向變量。
首先需要明白的是:引用不同於指針。
通俗的講(個人理解),引用就是一個人的小名。看,比如指明瞭我這個大名:
int zzw = 8;
即8是我的身體,而zzw是代表我這個身體的大名 。
但是我還可以起一個小名,如下:
int& pig = zzw;
也就是說無論是大名zzw還是小名pig都指得是我自己, 叫我什麼我都答應。
實例如下:
#include <iostream> using namespace std;int main () { int zzw = 8; int& pig = zzw; cout << zzw << endl << pig << endl; cout << "對引用進行修改" <<endl; pig = 20; cout << zzw << endl << pig; return 0; }
最終的結果如下所示:
88對引用進行修改2020
可以看到叫我小名我也答應你了(修改一個變量的引用,實際上就是修改它自己)。
19. C++數據結構
在C和C++的數組中可以定義存儲相同數據類型的變量。 但是在C++中還提供了數據結構,在這個數據結構裏我們可以定義不同類型的變量。
具體應用舉例如下:
#include <iostream> #include <cstring> using namespace std; // 聲明一個結構體類型 Books struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; int main( ) { Books Book1; // 定義結構體類型 Books 的變量 Book1 Books Book2; // 定義結構體類型 Books 的變量 Book2 // Book1 詳述 strcpy( Book1.title, "C++ 教程"); strcpy( Book1.author, "Runoob"); strcpy( Book1.subject, "編程語言"); Book1.book_id = 12345; // Book2 詳述 strcpy( Book2.title, "CSS 教程"); strcpy( Book2.author, "Runoob"); strcpy( Book2.subject, "前端技術"); Book2.book_id = 12346; // 輸出 Book1 信息 cout << "第一本書標題 : " << Book1.title <<endl; cout << "第一本書作者 : " << Book1.author <<endl; cout << "第一本書類目 : " << Book1.subject <<endl; cout << "第一本書 ID : " << Book1.book_id <<endl; // 輸出 Book2 信息 cout << "第二本書標題 : " << Book2.title <<endl; cout << "第二本書作者 : " << Book2.author <<endl; cout << "第二本書類目 : " << Book2.subject <<endl; cout << "第二本書 ID : " << Book2.book_id <<endl; return 0; }
另外,數據結構也可以作爲參數傳遞進去,如下所示:
#include <iostream> #include <cstring> using namespace std; void printBook( struct Books book ); // 聲明一個結構體類型 Books struct Books { char title[50]; char author[50]; char subject[100]; int book_id; }; int main( ) { Books Book1; // 定義結構體類型 Books 的變量 Book1 Books Book2; // 定義結構體類型 Books 的變量 Book2 // Book1 詳述 strcpy( Book1.title, "C++ 教程"); strcpy( Book1.author, "Runoob"); strcpy( Book1.subject, "編程語言"); Book1.book_id = 12345; // Book2 詳述 strcpy( Book2.title, "CSS 教程"); strcpy( Book2.author, "Runoob"); strcpy( Book2.subject, "前端技術"); Book2.book_id = 12346; // 輸出 Book1 信息 printBook( Book1 ); // 輸出 Book2 信息 printBook( Book2 ); return 0; } void printBook( struct Books book ) { cout << "書標題 : " << book.title <<endl; cout << "書作者 : " << book.author <<endl; cout << "書類目 : " << book.subject <<endl; cout << "書 ID : " << book.book_id <<endl; }
20. C++中的函數重載
文章C++的函數重載無疑是非常棒的,這裏僅僅摘錄一部分做一個簡單的瞭解,日後必定深入。
1. 什麼是函數重載?
函數重載是指在同一作用域內,可以有一組具有相同函數名,不同參數列表的函數,這組函數被稱爲重載函數。重載函數通常用來命名一組功能相似的函數,這樣做減少了函數名的數量,避免了名字空間的污染,對於程序的可讀性有很大的好處。
下面就是函數重在的例子,即實現一個打印函數:
#include<iostream>using namespace std;void print(int i) { cout<<"print a integer :"<<i<<endl; }void print(string str) { cout<<"print a string :"<<str<<endl; }int main() { print(12); print("hello world!"); return 0; }
最終的輸出如下:
print a integer :12print a string :hello world!
即我們調用函數名相同的函數(實現的功能也大抵相似)返回的值確實不同的。
2.爲 什麼要函數重載?
試想如果沒有函數重載機制,如在C中,你必須要這樣去做:爲這個print函數取不同的名字,如print_int、print_string。這裏還只是兩個的情況,如果是很多個的話,就需要爲實現同一個功能的函數取很多個名字,如加入打印long型、char*、各種類型的數組等等。這樣做很不友好!
類的構造函數跟類名相同,也就是說:構造函數都同名。如果沒有函數重載機制,要想實例化不同的對象,那是相當的麻煩!
操作符重載,本質上就是函數重載,它大大豐富了已有操作符的含義,方便使用,如+可用於連接字符串等。
補充:
http://www.cnblogs.com/lzjsky/archive/2011/01/24/1943199.html
靜態數據成員介紹
結束,有時間了再繼續...
2017年3月31日更新(C++進階)
今天剛剛使用MinGW 和 nodepad++ 來編譯和執行文件了,和visual C++ 6.0是一樣的可以cin也可以cout,還是非常激動的,趁此就多複習一些知識吧。
1. 下面這是一個含有類和對象的最簡單的例子:
#include <iostream>using namespace std;class Person // L類的定義{public: void SetInfo() { cout<<"Input info to name,sex,age"<<endl; cin>>name>>sex>>age; } void Show() { cout<<"name:"<<name; cout<<"sex:"<<sex; cout<<"age:"<<age<<endl; }private: char name[20]; char sex[2]; int age; }; // 類聲明結束,必須要有分號int main() { Person person1,person2; person1.SetInfo(); person2.SetInfo(); person1.Show(); person2.Show(); return 0; }
其中class Person用來定義一個名爲Person的類,可以把類看做一個模子,然後我們用這個模子就可以創造形形色色的對象來了。值得注意的是,在class定義了之後,需要使用分號作爲結束。
另外,使用public是說其中的內容是公有的,可以被調用的,而privite是私有的,只能在內部被調用。這就體現了著名的封裝性的特點。
這就是面向對象,它引入了類和對象的概念,類是用戶自定義的數據類型,對象是該數據類型的變量。
2. 注意使用#define 定義常變量時,只是將變量進行了簡單的替換,如下所示:
int x=1; int y=2; #define R x+y #define PI 3.1415926 cout<<PI*R*R; 最後實際輸出的是 PI*1+2*1+2 而不是PI*(1+2)*(1+2)
而如果我們使用const float PI = 3.14;也是類似的作用,也可以寫成 float const PI = 3.14; 兩者是等效的。
3、空指針和野指針
int *p = 0; 或者是 int *p = NULL; 那麼這裏的p就是空指針。
而int *q; 僅僅聲明瞭這個指針q,但是不知道它指向了哪裏,所以說是野的,即野指針。
兩者是不同的,引入空指針的目的是爲了防止使用指針出錯,如果出現了空指針就會報錯,情況:動態分配內存malloc()函數或new運算符的成功使用不會返回空指針,但是失敗了就會返回空指針。
如果定義了一個野指針,我們就不知道它到底會指向何處,爲了避免不知指針指向了何處,在C++中一般習慣是定義了指針變量後立即初始化爲空指針,然後在使用指針之前再給指針變量賦值,使指針有了具體指向之後再使用指針。
4. 指針與const
const int *p;(int const *p; 和前者是一樣的) 這個的意思p是常量,即我們不能通過 *p 來修改p所指向的值,但是可以直接修改p所指向的值, 也可以修改p的指向。
#include <iostream>using namespace std;int main() { const int *p = NULL; int a = 20; int b = 30; p = &a; p = &b; *p = 50; // error: assignment of read-only location "*p" cout<<*p; }
我們可以修改b的值,這樣*p會改變,也可以修改p的指向,但是如果通過*p來修改指向的值就報錯,提示*p是隻讀的。
int *const p; 這裏是指p指針是const的,一旦定義了,就不能修改p的指向。
#include <iostream>using namespace std;int main() { int *const p = NULL; int a = 20; int b = 30; p = &a; // 報錯 cout<<*p; }
這裏我已經定義p爲空指針了,那麼後面p又指向a就會報錯。
const int *const p; 這裏就是上述的綜合,即不能修改p的指向也不能通過*p來修改p所指向的值。
5. void和void指針
先說void , 函數 int func(void){return 0;} 和int func(){return 0;}在C++中都表示不接受任何參數,如果使用func(2)就會報錯。但是在c語言中,如果我們使用func(2)就不會報錯,所以,爲了更加嚴謹,最好使用void表示不接受參數。 另外我們不能使用void a;這種形式來聲明變量,因爲void表示無類型的,如果你聲明瞭這個變量,那麼分配多少內存呢? 對吧。
但是void是可以聲明一個指針的。 答案是可以的。使用void聲明一個指針,我們就稱爲“無類型指針”,或者就稱爲void指針。 我們知道,一個類型的指針必須指向相同類型的變量,但是void指針就厲害了,它可以指向任意類型的變量。但是void類型的指針在讀取值和指針的賦值過程中需要進行強制類型轉換,原因如下:
不難想象,無論是什麼類型的指針,它指向一個變量的首地址總是一樣的,所以我們纔可以使用void指針,但問題是: 如果我們希望通過這個指針來訪問他所指向的變量,就得知道這個變量的類型啊,因爲不同類型的變量的內存大小是不一樣的,所以得強制類型轉化,告訴它這個變量的大小是多少,纔可以讀取。
#include <iostream>using namespace std;int main() { void *p; int a = 5; double b = 10; p = &a; cout<< *(int *)p; }
如上,必須進行強制類型轉換才能正確的輸出p所指向的變量,注意:強制類型轉換是(int *)因爲這是一個指針。
6. 使用new和delete動態管理內存單元
和聲明一個變量不同,使用new一般是用來申請指針的內存單元的,並且前者是在編譯過程中分配的內存,而後者是在程序的執行過程中才分配的內存,所以是動態分配內存。 另外,new之後一定要delete,因爲聲明的方式可以自動地清除內存,但是new的方式只能使用delete來清除內存。
#include <iostream>using namespace std;int main() { int *p = NULL; p = new int; delete p; cout<<*p; }
最終輸出的是16323288, 注意這是new到的一個內存,所以這是一個隨機數。 且new和delete必須要成對存在。我們還可以在new的時候初始化,即p = new int(20); 那麼*p就是20了。
那我們怎麼申請連續空間的內存呢? 方法也很簡單,就是p = new int[20]; 這樣就可以申請到長度爲20的連續空間了。
7. 引用,如 int &a = b;這就是a對b的引用,可以看做a是b的另外一個名字,但是他們指向的同一個內存單元,所以對他們任意一個的修改都是有效的。 下面我們看三個典型的例子,分別是值傳遞、指針傳遞和引用傳遞。
#include <iostream>using namespace std;int fun(int a, int b) { int temp; temp = a; a = b; b = temp; }int main() { int x = 5, y = 10; cout<<" x:"<<x<<" y:"<<y<<endl; fun(x,y); cout<<" x:"<<x<<" y:"<<y<<endl; }
最後的結果都是x爲5,y爲10。這就是典型的值傳遞,即穿進去之後,內部的改變不會影響外面的。
#include <iostream>using namespace std;int fun(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; }int main() { int x = 5, y = 10; cout<<" x:"<<x<<" y:"<<y<<endl; fun(&x,&y); cout<<" x:"<<x<<" y:"<<y<<endl; }
最後的結果是: x:5,y:10 後面是x:10,y:5 可以發現這個交換就完成了。 這就是典型的指針傳遞或地址傳遞。這樣,在內部修改的*a和*b實際上就在修改x和y。
#include <iostream>using namespace std;int fun(int &a, int &b) { int temp; temp = a; a = b; b = temp; }int main() { int x = 5, y = 10; cout<<" x:"<<x<<" y:"<<y<<endl; fun(x,y); cout<<" x:"<<x<<" y:"<<y<<endl; }
最後的結果是: x:5,y:10 後面是x:10,y:5 可以發現這個交換就完成了。 這就是典型的引用傳遞,兩者都是指向同樣的內存,所以可以完成修改。
值得注意的是,在引用中,還是有const的,如const int &a = b;表示a這個引用是不能被修改的,即不能通過a來修改他和b共有的內存,即a的權利只是讀。如下:
#include <iostream>using namespace std;int main() { int x=10; const int &b = a; b = 20; cout<<a; }
編譯過程中就會提示b是隻讀的。
8. 函數的相關問題
在c++中,無論你寫了多少,總是從main函數中開始執行,並且在調用一個函數之前,我們必須進行函數聲明(函數聲明和函數定義不同,所以說需要用分號作爲結尾),另外,main函數是最重要的,我們強烈建議將函數定義寫在main函數之後,另外, 在函數聲明的時候我們只需要將函數的類型聲明即可, 名稱不重要,編譯時不會檢查。
除此之外,我們還可以提供默認的參數,即如果沒有傳遞該參數,我們就使用默認的。且默認的參數可以使其中的一個或幾個(當然可以使全部),但是如果不是全部時, 默認的參數需從最右邊開始。
#include <iostream>using namespace std;int main() { int add(int,int,int =50); //int add(int,int,int c=50); // 這個也是有效的,在函數什麼聲明的過程中,不需要制定名字。 cout<<add(5,10,15)<<endl; // 30 cout<<add(5,10); }int add(int a,int b,int c = 50) { return a + b + c; }
值得注意的是,如果使用默認參數,那麼定義和聲明都需要指明默認的值,否則就會報錯。 雖然我們可以直接寫在int main()的上面,這樣就不需要聲明瞭,但是這並不是我們所推薦的。
函數重載: 即函數參數的類型不同或個數不同或函數參數的類型和個數都不相同。函數的返回值可以相同也可以不同,但是絕不能函數的參數形同而只有返回值不同,這不是函數的重載。如下:
#include <iostream>using namespace std;int main() { int add(int,int); int add(int,int,int); int a = 5,b = 8; int x = 14,y = 15, z =45; cout<<add(a,b)<<endl<<add(x,y,z); }int add(int a, int b, int c) { return a+b+c; }int add(int a, int b) { return a+b; }
一個輸出的是13,另一個輸出的是74。
9. 詳解名字空間
我之前所寫的所有代碼中都包括: using namespace std; 不難理解,這一定和命名空間是由關係的。下面我將從頭說起。。。
(1)爲什麼要使用名字空間?
簡單的說,使用名字空間是爲了解決程序中名字衝突的問題,即在程序運行過程中遇到相同名字的變量,系統不能正確的區分它們。
在一個小型系統裏,只要我們注意一下變量就不會重複,但是對於一個大型的系統,由多人合作完成,我們通過#include的方式來引入不同的開發人員所編寫的程序,那就難免會遇到重名的情況,這樣就導致類全局名字空間污染。
正是爲了避免這樣的問題,後來引入了名字空間的機制。(在早期的C++中,也是沒有名字空間的概念的)。
(2)什麼是名字空間?
所謂名字空間就是一個由程序設計者命名的內存區域。他可以根據需要建立一些有名字的命名空間域,把一些全局標識符分別放在不同的名字空間中,這樣就可以解決變量衝突的問題了。 就向一個文件下有一個目錄,每個子目錄又有一堆文件,那麼各個目錄下的文件是可以重名的,於是就解決了問題。
(3)如何使用名字空間?
語法如下:
namespace 名字空間名 { 定義成員 }
其中成員的類型包括:常量、變量、函數、結構體、類、模板等,還可以是名字空間,即名字空間的嵌套。如下:
namespace ns { const int RATE = 0.08; double money; double tax() { return money * RATE; } namespace ns2 { int count; } }
如果要訪問名字空間ns中的成員,就可以採用“名字空間::成員名”的方法,如ns::RATE、ns::money、ns::tax()、ns2::count等等。
我們還可以給ns起一個別名,即namespace anotherns = ns; 那麼就是anotherns::money就和 ns::money的效果是一樣的了。
技巧: 使用using 名字空間的成員名,如using ns::tax 後面再訪問tax()的時候就相當於ns::tax(),這樣可以避免在每一次訪問名字空間的成員時用名字空間限定,來簡化名字空間的使用。
技巧: 使用using 名字空間名, 如果在一段程序中經常訪問一個名字空間中的多個成員,就要多次使用using名字空間成員名,這是很不方便的,所以C++提供了using namespace 語句,一次就能聲明一個名字空間中的全部成員,格式爲:
using namespace 名字空間名;
注意1: 該聲明下使用變量只在該聲明的作用域內有效。
注意2: 如果同時使用using namespace引入了多個命名空間,那麼要保證它們沒有相同的變量名,否則還是會有命名衝突。
(4)標準名字空間 std
即standard,標準的名字空間,系統預定義的頭文件中的函數、類、對象和類模板都是在std中定義的。
所以,第二行都有一個using namespace std; 這就在全局中起作用了,如果不用的話,我們就要使用std::來訪問了,如下所示:
#include <iostream>int main() { std::cout << "Hello world"; }
如果引入了大量的系統的函數、類等,我們就需要添加沒玩沒了的std::,然後這是很不方便的。
9. 字符串變量
我們知道在c中使用char來定義字符串和字符串數組都是十分麻煩的。而在c++中,由於有了類的概念,並且系統自帶的就有string類,我們只要在開頭引入即可,即#include <string>然後我們就可以使用string類了。
如 string str = "hello"; 這樣就定義了一個字符串變量,我們可以對這個變量進行大量的操作,如strcat、strcopy等等。另外,還可以賦值,並且不需要考慮內存的問題。
和c中的最大的不同是,在c中的字符串,最後自動添加'\0'作爲結尾,而string實例化的對象不需要使用'\0'作爲結尾。且可以使用str[0]等來訪問到每一個字符。
在c++中,還支持數組,如 string str = {"hello", "world", "hhahha"}; 即我們不需要考慮每一個元素的長度是否一致等。 就是這個方便。