文章目錄
- 1、C++中空類預設產生哪些類成員函數?
- 2、結構是否可以有建構函式、解構函式及成員函數?如果可以,那麼結構和類還有什麼區別嗎?
- 3、下面程式列印出的結果是什嗎?
- 4、下面這個類聲明正確嗎?為什嗎?
- 5、解構函式可以為 virtual 型,建構函式則不能,為什嗎?
- 6、如果虛函數是非常有效,我們是否可以把每個函數都聲明為虛函數?
- 7、請看下面一段程式:
- 8、編寫類 String 的建構函式、解構函式和賦值函數。
- 9、重載與覆蓋有什麼不同?
說到物件導向,大家第一反應應該就是它的三大特性:封裝性、繼承性和多態性。那麼我們先簡單的瞭解一下這三大特性:
(1)封裝性:封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者對象操作,對不可信的進行資訊隱藏。
在C++中類中成員的屬性有:public, protected, private,這三個屬性的存取權限依次降低。
(2)繼承性:繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴充。
(3)多態性:多態性(polymorphisn)是允許你將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指標賦值給父類類型的指標。實現多態,有二種方式,覆蓋,重載。
覆蓋,是指子類重新定義父類的虛函數的做法。
重載,是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。
下面開始我們今天的學習。
1、C++中空類預設產生哪些類成員函數?
答案:
對於一個空類,編譯器預設產生4個成員函數:
(1)預設建構函式
(2)解構函式
(3)拷貝建構函式
(4)賦值函數
2、結構是否可以有建構函式、解構函式及成員函數?如果可以,那麼結構和類還有什麼區別嗎?
答案:
區別是class中變數預設是private,struct中的變數預設是public。class繼承預設是private繼承,而struct繼承預設是public繼承。struct可以有建構函式、解構函式,之間也可以繼承甚至是多重繼承,等等。C++中的struct其實和class意義一樣,唯一不同就是struct裡面預設的存取控制是public,class中預設存取控制是private。C++中存在struct關鍵字的唯一意義就是為了讓C程式員有個歸屬感,是為了讓C++編譯器相容以前用C開發的項目。
3、下面程式列印出的結果是什嗎?
#include<iostream>using namespace std;class base{private:int m_i;int m_j;public:base( int i ) : m_j(i),m_i(m_j) {}base() : m_j(0),m_i(m_j){}int get_i() {return m_i;}int get_j() {return m_j;}};int main (){base obj(98);cout << obj.get_i() <<endl<< obj.get_j() <<endl;return 0;}
解析:本題想得到的結果是“98,98”。但是成員變數的聲明是先 m_i ,然後是 m_j;初始化列表的初始設定變數順序是根據成員變數的聲明順序來執行的,因此,先初始化 m_i,但此時 m_j 還未初始化,m_i 會被賦予一個隨機值。改變一下成員變數的聲明順序可以得到預想的結果。
答案:
輸出結果第一個為隨機數,第二個是98。
4、下面這個類聲明正確嗎?為什嗎?
class A {const int Size = 0;};
解析:這道程式題存在著成員變數問題。常量必須在建構函式的初始化列表裡初始化或者將其設定成static。
答案:
正確的程式如下:
class A{A(){const int Size = 1;}};
或者:
class A{static const int Size = 1;};
5、解構函式可以為 virtual 型,建構函式則不能,為什嗎?
答案:
虛函數採用一種虛調用的辦法。虛調用是一種可以在只有部分資訊的情況下工作的機制,特別允許我們調用一個只知道介面而不知道其準確物件類型的函數。但是如果要建立一個對象,你勢必要知道對象的準確類型,因此建構函式不能為 virtual。
6、如果虛函數是非常有效,我們是否可以把每個函數都聲明為虛函數?
答案:
不行,這是因為虛函數是有代價的:由於每個虛函數的對象都必須維護一個 v 表,因此在使用虛函數的時候會產生一個系統開銷。如果僅是一個很小的類,且不行派生其他類,那麼根本沒必要使用虛函數。
7、請看下面一段程式:
#include<iostream>using namespace std;class B{private:int data;public:B(){cout<<"defualt constructor"<<endl;}~B(){cout<<"destructed "<<endl;}B( int i) : data(i){cout<<"constructed by parameter"<<data<<endl;}};B Play( B b ){return b;}int main (){B temp = Play(5);return 0;}
問題:
(1)該程式輸出結果是什嗎?為什麼會有這樣的輸出?
(2)B( int i ) : data( i ),這種用法的專業術語叫什嗎?
(3)Play( 5 ),形參類型是類,而5是個常量,這樣寫合法嗎?為什嗎?
答案:
(1)輸出結果如下:
constructed by parameter//在Play(5)處,5通過隱含的類型轉換調用了B::B( int i ) destructed //Play(5) 返回時,參數的解構函式被調用 destructed //temp的解構函式被調用;temp的建構函式調用的是編譯器生存的拷貝建構函式
(2)待參數的建構函式,冒號後面的是成員變數初始化列表(member initialization list)
(3)合法。單個參數的建構函式如果不添加explicit關鍵字,會定義一個隱含的類型轉換;添加explicit關鍵字會消除這種隱含轉換。
8、編寫類 String 的建構函式、解構函式和賦值函數。
已知類 String 的原型為:
class String{public:String(const char *str = NULL); //普通建構函式String(const String &other); //拷貝建構函式~String(void); //解構函式String & operate =(const String &other); //賦值函數private:char *m_data; //用於儲存字串};
答案:
1、 String 的解構函式:
String::~String(void){delete [] m_data;}
2、String 的建構函式:
String::String(const char *str){if(NULL==str){m_data = new char[1];*m_data = '\0';}else{int length = strlen(str);m_data = new char[length+1];strcpy(m_data,str);}}
3、String的拷貝建構函式:
String::String(const String &other){int length = strlen(other.m_data);m_data = new char[length+1];strcpy(m_data,other.m_data);}
4、String的賦值函數:
String & String::operate =(const String &other){if(this== &other) //檢查自複製{return *this;}delete [] m_data; //釋放原有的記憶體資源int length=strlen(other.m_data); //分配新記憶體資源,並複製內容m_data = new char[length+1];strcpy(m_data,other.m_data);return *this; //返回本對象的引用}
9、重載與覆蓋有什麼不同?
答案:
虛函數總是在衍生類別中被改寫,這種改寫被稱為“override”(覆蓋)。
override 是指衍生類別重寫基類的虛函數,重寫的函數必須有一致的參數表和傳回值。Override這個單詞好像一直沒什麼合適的中文詞彙來對應。有些人譯為“覆蓋”,還貼切一些。
overload約定成俗地被翻譯為“重載”,是指編寫一個與自己已有函數同名但是參數表不同的函數。例如一個函數既可以接受整型數作為參數,也可以接收浮點數作為參數。重載不是一種物件導向的編程,而是一種文法規則,重載與多態沒什麼直接關係。