[C++]基礎題目總結

C++期末複習

1、選擇題考察的知識點(40分)

 

C++在C的基礎上多了什麼新特性

  • 類和對象
  • 繼承
  • 多態、虛函數和RTT1(運行階段類型識別)
  • 函數重載
  • 引用變量
  • 泛型(獨立於類型的)編程,這種技術是由模版和標準模版庫(STL)提供的
  • 處理錯誤條件的異常機制
  • 管理函數、類和變量名的名稱空間

 

編寫C++程序的步驟

一、用C++語言編寫程序
用高級語言編寫的程序稱爲「源程序」(source program)。C++的源程序是以.cpp做爲後綴的(cpp是c plus plus 的縮寫)。
二、對源程序進行編譯
爲了使計算機能執行高級語言源程序,必須先用一種稱爲「編譯器(complier)」的軟件(也稱編譯程序或編譯系統),把源程序翻譯成二進制形式的「目標程序(object program)」。
編譯是以源程序文件爲單位分別編譯的。目標程序通常以.obj或.o做爲後綴(object 的縮寫)。編譯的做用是對源程序進行詞法檢查和語法檢查。編譯時對文件中的所有內容進行檢查,編譯結束後會顯示出全部的編譯出錯信息。通常編譯系統給出的出錯信息分爲兩種,一種是錯誤(error);一種是警告(warning) 。
三、將目標文件鏈接
在改正全部的錯誤並所有經過編譯後,獲得一個或多個目標文件。此時要用系統提供的「鏈接程序(linker)」將一個程序的全部目標程序和系統的庫文件以及系統提供的其餘信息鏈接起來,最終造成一個可執行的二進制文件,它的後綴是.exe,是能夠直接執行的。
四、運行程序
運行最終造成的可執行的二進制文件(.exe文件),獲得運行結果。
五、分析運行結果
若是運行結果不正確,應檢查程序或算法是否有問題。

 

C++中合法標識符的特徵

第一個字符必須是字母(不分大小寫)或下劃線(_);
後跟字母(不分大小寫)、下劃線(_)或數字組成;
標識符中的大小寫字母有區別;
不能與c編譯系統已經預約義的、具備特殊用途的保留標識符(即關鍵字)同名。好比,不能將標識符命名爲float,auto,break,case,this,try,for,while,int,char,short, unsigned,等等;html

 

算符優先級(重點考察算術運算符、邏輯運算符和賦值運算符)

 

C++運算符優先級表,從上到下,從左到右,優先級依次減弱。
優先級 運算符 說明 結合性
1 :: 範圍解析 自左向右
2 ++  -- 後綴自增/後綴自減
() 括號
[] 數組下標
. 成員選擇(對象)
−> 成員選擇(指針)
3 ++  -- 前綴自增/前綴自減 自右向左
+  − 加/減
!  ~ 邏輯非/按位取反
(type) 強制類型轉換
* 取指針指向的值
& 某某的地址
sizeof 某某的大小
new,new[] 動態內存分配/動態數組內存分配
delete,delete[] 動態內存釋放/動態數組內存釋放
4 .*  ->* 成員對象選擇/成員指針選擇 自左向右
5 *  /   % 乘法/除法/取餘
6 +  − 加號/減號
7 <<  >> 位左移/位右移
8 <  <= 小於/小於等於
>  >= 大於/大於等於
9 ==  != 等於/不等於
10 & 按位與
11 ^ 按位異或
12 | 按位或
13 && 與運算
14 || 或運算
15 ?: 三目運算符 自右向左
16 = 賦值
+=  −= 相加後賦值/相減後賦值
*=  /=   %= 相乘後賦值/相除後賦值/取餘後賦值
<<=  >>= 位左移賦值/位右移賦值
&=  ^=  |= 位與運算後賦值/位異或運算後賦值/位或運算後賦值
17 throw 拋出異常
18 , 逗號 自左向右

 

算術表達式、邏輯表達式

算術運算符

下表顯示了 C++ 支持的算術運算符。c++

假設變量 A 的值爲 10,變量 B 的值爲 20,則:算法

運算符 描述 實例
+ 把兩個操做數相加 A + B 將獲得 30
- 從第一個操做數中減去第二個操做數 A - B 將獲得 -10
* 把兩個操做數相乘 A * B 將獲得 200
/ 分子除以分母 B / A 將獲得 2
% 取模運算符,整除後的餘數 B % A 將獲得 0
++ 自增運算符,整數值增長 1 A++ 將獲得 11
-- 自減運算符,整數值減小 1 A-- 將獲得 9

邏輯運算符

下表顯示了 C++ 支持的關係邏輯運算符。編程

假設變量 A 的值爲 1,變量 B 的值爲 0,則:小程序

運算符 描述 實例
&& 稱爲邏輯與運算符。若是兩個操做數都非零,則條件爲真。 (A && B) 爲假。
|| 稱爲邏輯或運算符。若是兩個操做數中有任意一個非零,則條件爲真。 (A || B) 爲真。
! 稱爲邏輯非運算符。用來逆轉操做數的邏輯狀態。若是條件爲真則邏輯非運算符將使其爲假。 !(A && B) 爲真。

 

條件判斷語句if的使用方法

 

 

 

循環語句(while, for)的使用方法

while循環語法

C++ 中 while 循環的語法:數組

while(condition)
{
   statement(s);
}

在這裏,statement(s) 能夠是一個單獨的語句,也能夠是幾個語句組成的代碼塊。condition 能夠是任意的表達式,當爲任意非零值時都爲真。當條件爲真時執行循環。編程語言

當條件爲假時,程序流將繼續執行緊接着循環的下一條語句。函數

流程圖

C++ 中的 while 循環

在這裏,while 循環的關鍵點是循環可能一次都不會執行。當條件被測試且結果爲假時,會跳過循環主體,直接執行緊接着 while 循環的下一條語句。post

 

for循環語法

C++ 中 for 循環的語法:性能

for ( init; condition; increment )
{
   statement(s);
}

下面是 for 循環的控制流:

  1. init 會首先被執行,且只會執行一次。這一步容許您聲明並初始化任何循環控制變量。您也能夠不在這裏寫任何語句,只要有一個分號出現便可。
  2. 接下來,會判斷 condition。若是爲真,則執行循環主體。若是爲假,則不執行循環主體,且控制流會跳轉到緊接着 for 循環的下一條語句。
  3. 在執行完 for 循環主體後,控制流會跳回上面的 increment 語句。該語句容許您更新循環控制變量。該語句能夠留空,只要在條件後有一個分號出現便可。
  4. 條件再次被判斷。若是爲真,則執行循環,這個過程會不斷重複(循環主體,而後增長步值,再而後從新判斷條件)。在條件變爲假時,for 循環終止。

流程圖

 

函數默認參數的使用方法(注意默認參數和非默認參數的順序)

① 有函數聲明(原型)時,默認參數能夠放在函數聲明或者定義中,但只能放在兩者之一

double sqrt(double f = 1.0); //函數聲明

double sqrt(double f)  //函數定義
{
  // ....  
} 

 

② 沒有函數(原型)時,默認參數在函數定義時指定.

//沒有 函數聲明

double sqrt(double f = 1.0)  //函數定義

 

③ 在具備多個參數的函數中指定默認值時,默認參數都必須出如今不默認參數的右邊,一旦某個參數開始指定默認值,它右邊的全部參數都必須指定默認值.

int f (int i1, int i2 = 2, int i3 = 3);     // 正確
int g (int i1, int i2 = 2, int i3);         // 錯誤, i3未指定默認值
int h (int i1 = 1, int i2, int i3 = 3);     // 錯誤, i2未指定默認值

 

④ 在調用具備默認參數的函數時, 若某個實參默認,其右邊的全部實參都應該默認。

//例如, 一個函數聲明以下
int f(int i1 = 1, int i2 =2, int i3 = 3);


//調用函數 f()
f();             //正確, i1=1, i2=2, i3=3
f(3);            //正確, i1=3, i2=2, i3=3
f(2, 3);         //正確, i1=2, i2=3, i3=3
f(4, 5, 6);      //正確, i1=4, i2=5, i3=6
f(, 2, 3);       //錯誤, i1默認,其右邊的i2和i3沒有默認

 

重載函數的定義

一.重載函數的定義

函數的重載是一種特殊狀況,C++容許在同一做用域中聲明幾個相似的同名函數,這些同名函數的形參列表

(參數個數,類型,順序)必須不一樣,經常使用來處理實現功能相似數據類型不一樣的問題。

在C++中不只函數能夠重載,運算符也能夠重載。

運算符<<>>。既能夠作移位運算符,也能夠作輸出,輸入運算符。
注意:重載函數的參數個數,參數類型或參數順序三者中必須有一個不一樣。

 

函數重載的規則:

*函數名稱必須相同。

*參數列表必須不一樣(個數不一樣,類型不一樣,參數排列順序不一樣等)。

*函數的返回類型也能夠相同也能夠不相同。

*僅僅返回類型不一樣不足以成爲函數的重載。

 

二.函數重載的做用

重載函數一般用來在同一做用域內 用同一個函數名 命名一組功能類似的函數,

這樣作減小了函數名的數量,避免了名字空間的污染,也大大方便了代碼的書寫,可讀性很強。

 

三.重載底層編譯的原理

由於函數名同樣,咱們根據參數列表對函數進行重命名,

這樣的話底層編譯就能夠識別不一樣功能的重載函數了。

例:

void Swap(int a , int b);

         Swap_int_int;

        void Swap(float a, float b);

       Swap_float_float;

       void Swap(float a, float b);

       Swap_float_float;

 

咱們能夠這樣去理解,先重命名函數,再去調用函數。

 

數組的定義,數組下標的範圍,數組元素的使用方法(下標引用,指針引用)

菜鳥教程(數組) https://www.runoob.com/cplusplus/cpp-arrays.html

 

初始化字符數組的方法(注意字符串以’\0’結尾,多佔一個字符)

發現了一個字符數組初始化的誤區,而這個每每能致使比較嚴重的性能問題,分析介紹以下:
每每咱們在初始化一個字符 數組,大概有以下幾種寫法:

char array1[1024] = "";
char array2[1024] = {0};
char array3[1024] = {'\0'};
char array4[1024];
array4[0] = '\0';

 

但這四種寫法,其實表明含義不一樣,看起來前三種寫法只是將array的第一個字符置爲0,其實前三種在gcc編譯時,都是調用了memset來將整個array置爲0,若是這個array很長,其實也會致使性能問題。我寫了一個簡單的小程序編譯生成test,objdump了一 下,執行「objdump -S test」能夠看下面的代碼:

 1 int main() {  2 400698: 55 push %rbp  3 400699: 48 89 e5 mov %rsp,%rbp  4 40069c: 48 81 ec 00 10 00 00 sub $0x1000,%rsp  5 char array1[1024] = "";  6 4006a3: 0f b6 05 42 01 00 00 movzbl 322(%rip),%eax # 4007ec <_IO_stdin_used+0x4>  7 4006aa: 88 85 00 fc ff ff mov %al,0xfffffffffffffc00(%rbp)  8 4006b0: 48 8d bd 01 fc ff ff lea 0xfffffffffffffc01(%rbp),%rdi  9 4006b7: ba ff 03 00 00 mov $0x3ff,%edx 10 4006bc: be 00 00 00 00 mov $0x0,%esi 11 4006c1: e8 fa fe ff ff callq 4005c0 <memset@plt> //調用了memset 12 13 char array2[1024] = {0}; 14 4006c6: 48 8d bd 00 f8 ff ff lea 0xfffffffffffff800(%rbp),%rdi 15 4006cd: ba 00 04 00 00 mov $0x400,%edx 16 4006d2: be 00 00 00 00 mov $0x0,%esi 17 4006d7: e8 e4 fe ff ff callq 4005c0 <memset@plt> //調用了memset 18 19 char array3[1024] = {'\0'}; 20 4006dc: 48 8d bd 00 f4 ff ff lea 0xfffffffffffff400(%rbp),%rdi 21 4006e3: ba 00 04 00 00 mov $0x400,%edx 22 4006e8: be 00 00 00 00 mov $0x0,%esi 23 4006ed: e8 ce fe ff ff callq 4005c0 <memset@plt> //調用了memset 24 25 char array4[1024]; 26 array4[0] = '\0'; 27 4006f2: c6 85 00 f0 ff ff 00 movb $0x0,0xfffffffffffff000(%rbp) 28 29 return 0; 30 4006f9: b8 00 00 00 00 mov $0x0,%eax 31 }

因此,對這四種寫法,實際執行的代碼解釋以下:

char array1[1024] = ""; //第11行,調用memset將1023個字符置爲0
char array2[1024] = {0}; //第17行,調用memset將1024個字符置爲0
char array3[1024] = {'\0'}; //第23行,調用memset將1024個字符置爲0
char array4[1024];
array4[0] = '\0'; //只是將第一個字符置爲0

而對於字符數組,每每只是做爲一個字符串的臨時緩衝區使用,沒有必要將整個數組置爲0,因此第四種寫法每每就能達到初始化的目的。建議使用第四種寫法來初始化一個字符數組,這樣能節約不少性能消耗。

轉載需註明來源:http://www.cnblogs.com/yczcc/p/7595099.html

 

引用的創建方法

1. 引用基本用法

引用是c++對c的重要擴充。在c/c++中指針的做用基本都是同樣的,可是c++增長了另一種給函數傳遞地址的途徑,這就是按引用傳遞(pass-by-reference),它也存在於其餘一些編程語言中,並非c++的發明。

 

變量名實質上是一段連續內存空間的別名,是一個標號(門牌號)

程序中經過變量來申請並命名內存空間

經過變量的名字可使用存儲空間

 

對一段連續的內存空間只能取一個別名嗎?

c++中新增了引用的概念,引用能夠做爲一個已定義變量的別名。

基本語法:

Type& ref = val;

注意事項:

&在此不是求地址運算,而是起標識做用。

類型標識符是指目標變量的類型

必須在聲明引用變量時進行初始化。

引用初始化以後不能改變。

不能有NULL引用。必須確保引用是和一塊合法的存儲單元關聯。

能夠創建對數組的引用。

//1. 認識引用
void test01(){

    int a = 10;
    //給變量a取一個別名b
    int& b = a;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //操做b就至關於操做a自己
    b = 100;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //一個變量能夠有n個別名
    int& c = a;
    c = 200;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "c:" << c << endl;
    cout << "------------" << endl;
    //a,b,c的地址都是相同的
    cout << "a:" << &a << endl;
    cout << "b:" << &b << endl;
    cout << "c:" << &c << endl;
}
//2. 使用引用注意事項
void test02(){
    //1) 引用必須初始化
    //int& ref; //報錯:必須初始化引用
    //2) 引用一旦初始化,不能改變引用
    int a = 10;
    int b = 20;
    int& ref = a;
    ref = b; //不能改變引用
    //3) 不能對數組創建引用
    int arr[10];
    //int& ref3[10] = arr;
}

    //1. 創建數組引用方法一
    typedef int ArrRef[10];
    int arr[10];
    ArrRef& aRef = arr;
    for (int i = 0; i < 10;i ++){
        aRef[i] = i+1;
    }
    for (int i = 0; i < 10;i++){
        cout << arr[i] << " ";
    }
    cout << endl;
    //2. 創建數組引用方法二
    int(&f)[10] = arr;
    for (int i = 0; i < 10; i++){
        f[i] = i+10;
    }
    for (int i = 0; i < 10; i++){
        cout << arr[i] << " ";
    }
    cout << endl;

 

 

 

2. 函數中的引用

 

最多見看見引用的地方是在函數參數和返回值中。當引用被用做函數參數的時,在函數內對任何引用的修改,將對還函數外的參數產生改變。固然,能夠經過傳遞一個指針來作相同的事情,但引用具備更清晰的語法。

若是從函數中返回一個引用,必須像從函數中返回一個指針同樣對待。當函數返回值時,引用關聯的內存必定要存在。

//值傳遞
void ValueSwap(int m,int n){
    int temp = m;
    m = n;
    n = temp;
}
//地址傳遞
void PointerSwap(int* m,int* n){
    int temp = *m;
    *m = *n;
    *n = temp;
}
//引用傳遞
void ReferenceSwap(int& m,int& n){
    int temp = m;
    m = n;
    n = temp;
}
void test(){
    int a = 10;
    int b = 20;
    //值傳遞
    ValueSwap(a, b);
    cout << "a:" << a << " b:" << b << endl;
    //地址傳遞
    PointerSwap(&a, &b);
    cout << "a:" << a << " b:" << b << endl;
    //引用傳遞
    ReferenceSwap(a, b);
    cout << "a:" << a << " b:" << b << endl;
}

 

 

經過引用參數產生的效果同按地址傳遞是同樣的。引用的語法更清楚簡單:

1) 函數調用時傳遞的實參沒必要加「&」符

2) 在被調函數中沒必要在參數前加「*」符

引用做爲其它變量的別名而存在,所以在一些場合能夠代替指針。C++主張用引用傳遞取代地址傳遞的方式,由於引用語法容易且不易出錯。

 

不能返回局部變量的引用。

函數當左值,必須返回引用。

//返回局部變量引用
int& TestFun01(){
    int a = 10; //局部變量
    return a;
}
//返回靜態變量引用
int& TestFunc02(){    
    static int a = 20;
    cout << "static int a : " << a << endl;
    return a;
}
int main(){
    //不能返回局部變量的引用
    int& ret01 = TestFun01();
    //若是函數作左值,那麼必須返回引用
    TestFunc02();
    TestFunc02() = 100;
    TestFunc02();

    return EXIT_SUCCESS;
}

 

 

3. 引用的本質

 

引用的本質在c++內部實現是一個指針常量.

Type& ref = val; // Type* const ref = &val;

 

c++編譯器在編譯過程當中使用常指針做爲引用的內部實現,所以引用所佔用的空間大小與指針相同,只是這個過程是編譯器內部實現,用戶不可見。

//發現是引用,轉換爲 int* const ref = &a;
void testFunc(int& ref){
    ref = 100; // ref是引用,轉換爲*ref = 100
}
int main(){
    int a = 10;
    int& aRef = a; //自動轉換爲 int* const aRef = &a;這也能說明引用爲何必須初始化
    aRef = 20; //內部發現aRef是引用,自動幫咱們轉換爲: *aRef = 20;
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
    testFunc(a);
    return EXIT_SUCCESS;
}

 

 

4. 指針引用

 

在c語言中若是想改變一個指針的指向而不是它所指向的內容,函數聲明可能這樣:

void fun(int**);

給指針變量取一個別名。

Type* pointer = NULL;  

Type*& = pointer;

Type* pointer = NULL;  Type*& = pointer;

struct Teacher{
    int mAge;
};
//指針間接修改teacher的年齡
void AllocateAndInitByPointer(Teacher** teacher){
    *teacher = (Teacher*)malloc(sizeof(Teacher));
    (*teacher)->mAge = 200;  
}
//引用修改teacher年齡
void AllocateAndInitByReference(Teacher*& teacher){
    teacher->mAge = 300;
}
void test(){
    //建立Teacher
    Teacher* teacher = NULL;
    //指針間接賦值
    AllocateAndInitByPointer(&teacher);
    cout << "AllocateAndInitByPointer:" << teacher->mAge << endl;
    //引用賦值,將teacher自己傳到ChangeAgeByReference函數中
    AllocateAndInitByReference(teacher);
    cout << "AllocateAndInitByReference:" << teacher->mAge << endl;
    free(teacher);
}

 

 

對於c++中的定義那個,語法清晰多了。函數參數變成指針的引用,用不着取得指針的地址。

5. 常量引用

 

常量引用的定義格式:

const Type& ref = val;

 

常量引用注意:

1.字面量不能賦給引用,可是能夠賦給const引用

2.const修飾的引用,不能修改。

 

void test01(){
    int a = 100;
    const int& aRef = a; //此時aRef就是a
    //aRef = 200; 不能經過aRef的值
    a = 100; //OK
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
}
void test02(){
    //不能把一個字面量賦給引用
    //int& ref = 100;
    //可是能夠把一個字面量賦給常引用
    const int& ref = 100; //int temp = 200; const int& ret = temp;
}

 

 

 [const引用使用場景]

    常量引用主要用在函數的形參,尤爲是類的拷貝/複製構造函數。

將函數的形參定義爲常量引用的好處:

  • 引用不產生新的變量,減小形參與實參傳遞時的開銷。
  • 因爲引用可能致使實參隨形參改變而改變,將其定義爲常量引用能夠消除這種反作用。

    若是但願實參隨着形參的改變而改變,那麼使用通常的引用,若是不但願實參隨着形參改變,那麼使用常引用。

 

//const int& param防止函數中意外修改數據
void ShowVal(const int& param){
    cout << "param:" << param << endl;
}

 

 

面向對象中成員訪問標籤的使用方法:公有,私有,保護,注意三者的區別

C++中 public,protected, private 訪問標號小結

第一:private, public, protected 訪問標號的訪問範圍。
private:只能由1.該類中的函數、2.其友元函數訪問。
不能被任何其餘訪問,該類的對象也不能訪問。

protected:能夠被1.該類中的函數、2.子類的函數、以及3.其友元函數訪問。
但不能被該類的對象訪問。

public:能夠被1.該類中的函數、2.子類的函數、3.其友元函數訪問,也能夠由4.該類的對象訪問。
 
注:友元函數包括3種:設爲友元的普通的非成員函數;設爲友元的其餘類的成員函數;設爲友元類中的全部成員函數。

第二:類的繼承後方法屬性變化。
private 屬性不可以被繼承。
使用private繼承父類的protected和public屬性在子類中變爲private;
使用protected繼承,父類的protected和public屬性在子類中變爲protected;
使用public繼承,父類中的protected和public屬性不發生改變;

 

靜態數據成員初始化方法(注意,若是定義時沒賦初值,對於靜態成員會初始化爲0)

靜態成員的初始化:

與全局對象同樣對於靜態數據成員在程序中也只能提供一個定義,這意味着靜態數據成員的初始化不該該被放在頭文件中而應該放在含有類的非inline函數定義的文件中。

能在類中初始化的成員只有一種,那就是靜態常量成員。

class A
{  
private:
    static const int count = 0; // 靜態常量成員能夠在類內初始化
};

 

結論:

  1. 靜態常量數據成員能夠在類內初始化(即類內聲明的同時初始化),也能夠在類外,即類的實現文件中初始化,不能在構造函數中初始化,也不能在構造函數的初始化列表中初始化;
  2. 靜態很是量數據成員只能在類外,即類的實現文件中初始化,也不能在構造函數中初始化,不能在構造函數的初始化列表中初始化;
  3. 非靜態的常量數據成員不能在類內初始化,也不能在構造函數中初始化,而只能且必須在構造函數的初始化列表中初始化;
  4. 非靜態的很是量數據成員不能在類內初始化,能夠在構造函數中初始化,也能夠在構造函數的初始化列表中初始化;

 

構造函數、拷貝構造函數、析構函數的使用方法

菜鳥教程(構造&析構) https://www.runoob.com/cplusplus/cpp-constructor-destructor.html

 

虛函數的定義及使用方法(搞清楚虛函數的使用場景)

在某基類中聲明爲 virtual 並在一個或多個派生類中被從新定 義的成員函數,用法格式爲:virtual 函數返回類型 函數名(參數表) {函數體};實現多態性,經過指向派生類的基類指針或引用,訪問派生類中同名覆蓋成員函數。


  虛函數定義:簡單地說,那些被virtual關鍵字修飾的成員函數,就是虛函數。虛函數的做用,用專業術語來解釋就是實現多態性(Polymorphism),多態性是將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差別,而採用不一樣的策略。


  虛函數的做用:用同一個調用形式,既能調用派生類又能調用基類的同名函數。


  虛函數的使用方法是:


1. 在基類用virtual聲明成員函數爲虛函數。
這樣就能夠在派生類中從新定義此函數,爲它賦予新的功能,並能方便地被調用。在類外定義虛函數時,沒必要再加virtual。
2. 在派生類中從新定義此函數,要求函數名、函數類型、函數參數個數和類型所有與基類的虛函數相同,並根據派生類的須要從新定義函數體。
C++規定,當一個成員函數被聲明爲虛函數後,其派生類中的同名函數都自動成爲虛函數。所以在派生類從新聲明該虛函數時,能夠加virtual,也能夠不加,但習慣上通常在每一層聲明該函數時都加virtual,使程序更加清晰。若是在派生類中沒有對基類的虛函數從新定義,則派生類簡單地繼承其直接基類的虛函數。
3. 定義一個指向基類對象的指針變量,並使它指向同一類族中須要調用該函數的對象。
4. 經過該指針變量調用此虛函數,此時調用的就是指針變量指向的對象的同名函數。
經過虛函數與指向基類對象的指針變量的配合使用,就能方便地調用同一類族中不一樣類的同名函數,只要先用基類指針指向便可。若是指針不斷地指向同一類族中不一樣類的對象,就能不斷地調用這些對象中的同名函數。這就如同前面說的,不斷地告訴出租車司機要去的目的地,而後司機把你送到你要去的地方。

 

虛基類的使用方法,爲何要使用虛基類

在類的繼承中,若是咱們遇到這種狀況:
「B和C同時繼承A,而B和C都被D繼承」
在此時,假如A中有一個函數fun()固然同時被B和C繼承,而D按理說繼承了B和C,同時也應該能調用fun()函數。這一調用就有問題了,究竟是要調用B中的fun()函數仍是調用C中的fun()函數呢?在C++中,有兩種方法實現調用:
(注意:這兩種方法效果是不一樣的)

  1.     使用做用域標識符來惟一表示它們好比:B::fun()
  2.     另外一種方法是定義虛基類,使派生類中只保留一份拷貝。

 

繼承有哪幾種方式,每種方式的特色是什麼?

 

 

 

 

 

若是在定義派生類時在基類前沒有指定訪問標籤,默認狀況下是哪一種繼承的方式?

private 私有繼承

 

輸入輸出流對象的使用方法

 

new, delete語句的使用方法

對於計算機程序設計而言,變量和對象在內存中的分配都是編譯器在編譯程序時安排好的,這帶來了極大的不便,如數組必須大開小用,指針必須指向一個已經存在的變量或對象。對於不能肯定須要佔用多少內存的狀況,動態內存分配解決了這個問題。

    new和delete運算符是用於動態分配和撤銷內存的運算符。

1、new用法

1.開闢單變量地址空間

   使用new運算符時必須已知數據類型,new運算符會向系統堆區申請足夠的存儲空間,若是申請成功,就返回該內存塊的首地址,若是申請不成功,則返回零值。

    new運算符返回的是一個指向所分配類型變量(對象)的指針。對所建立的變量或對象,都是經過該指針來間接操做的,而動態建立的對象自己沒有標識符名。

 通常使用格式:
        格式1:指針變量名=new 類型標識符;
        格式2:指針變量名=new 類型標識符(初始值);
        格式3:指針變量名=new 類型標識符 [內存單元個數];

說明:格式1和格式2都是申請分配某一數據類型所佔字節數的內存空間;可是格式2在內存分配成功後,同時將一初值存放到該內存單元中;而格式3可同時分配若干個內存單元,至關於造成一個動態數組。例如:

    1)new int;  //開闢一個存放整數的存儲空間,返回一個指向該存儲空間的地址。int *a = new int 即爲將一個int類型的地址賦值給整型指針a

    2)int *a = new int(5) 做用同上,可是同時將整數空間賦值爲5

2.開闢數組空間

    對於數組進行動態分配的格式爲:

       指針變量名=new 類型名[下標表達式];
       delete [ ] 指向該數組的指針變量名;

    兩式中的方括號是很是重要的,二者必須配對使用,若是delete語句中少了方括號,因編譯器認爲該指針是指向數組第一個元素的指針,會產生回收不完全的問題(只回收了第一個元素所佔空間),加了方括號後就轉化爲指向數組的指針,回收整個數組。

    delete []的方括號中不須要填數組元素數,系統自知。即便寫了,編譯器也忽略。

    請注意「下標表達式」沒必要是常量表達式,即它的值沒必要在編譯時肯定,能夠在運行時肯定。

    一維: int *a = new int[100];    //開闢一個大小爲100的整型數組空間

    二維: int **a = new int[5][6]

    三維及其以上:依此類推.

    通常用法: new 類型 (初值)

2、delete用法

1. 刪除單變量地址空間

       int *a = new int;

       delete a;   //釋放單個int的空間

2. 刪除數組空間

       int *a = new int[5];

       delete []a;    //釋放int數組空間

3、使用注意事項

1. new 和delete都是內建的操做符,語言自己所固定了,沒法從新定製,想要定製new和delete的行爲,徒勞無功的行爲。

2. 動態分配失敗,則返回一個空指針(NULL),表示發生了異常,堆資源不足,分配失敗。

3. 指針刪除與堆空間釋放。刪除一個指針p(delete p;)實際意思是刪除了p所指的目標(變量或對象等),釋放了它所佔的堆空間,而不是刪除p自己(指針p自己並無撤銷,它本身仍然存在,該指針所佔內存空間並未釋放),釋放堆空間後,p成了空指針。

4. 內存泄漏(memory leak)和重複釋放。new與delete 是配對使用的, delete只能釋放堆空間。若是new返回的指針值丟失,則所分配的堆空間沒法回收,稱內存泄漏,同一空間重複釋放也是危險的,由於該空間可能已另分配,因此必須妥善保存new返回的指針,以保證不發生內存泄漏,也必須保證不會重複釋放堆內存空間。

5. 動態分配的變量或對象的生命期。咱們也稱堆空間爲自由空間(free store),但必須記住釋放該對象所佔堆空間,並只能釋放一次,在函數內創建,而在函數外釋放,每每會出錯。

6. 要訪問new所開闢的結構體空間,沒法直接經過變量名進行,只能經過賦值的指針進行訪問。

    用new和delete能夠動態開闢和撤銷地址空間。在編程序時,若用完一個變量(通常是暫時存儲的數據),下次須要再用,但卻又想省去從新初始化的功夫,能夠在每次開始使用時開闢一個空間,在用完後撤銷它。

什麼函數會有this指針?友元函數是成員函數嗎?友元的做用是什麼?

 

 

 

 

2、編程題(60分)

基本循環(1題)

編寫程序,計算下式的值 1-3+5-7….-99

編寫程序,計算並輸出半徑r = 1到r = 20之間半徑爲整數的圓形的面積,直到面積大於100爲止

水仙花數怎麼計算,完數怎麼計算等,具體看一下循環章節的練習題

 

數組使用方法(1題)

 

有以下矩陣,編寫三個函數,分別計算每行的和、每列的和,矩陣中最大元素所在的位置

編寫函數,求矩陣Y的值

 

字符串操做(1題)

給定一個字符串,寫函數判斷字符串中每一個數字字符出現的頻率

給定一個字符串,寫函數判斷字符串中是否包含另外一個字符串

給定一個字符串,寫函數判斷該字符串是否爲迴文字串(正讀反讀均相同)

 

面向對象編程(1題) ---- 多態章節

相關文章
相關標籤/搜索