程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [C++面試題]之面向對象

[C++面試題]之面向對象

編輯:C++入門知識

 

說到面向對象,大家第一反應應該就是它的三大特性:封裝性、繼承性和多態性。那麼我們先簡單的了解一下這三大特性:

 

     (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、下面程序打印出的結果是什麼?

01 #include<iostream> 

 

02 using namespace std; 

 

03   

 

04 class base 

 

05 { 

 

06 private: 

 

07     int m_i; 

 

08     int m_j; 

 

09 public: 

 

10     base( int i ) : m_j(i),m_i(m_j) {} 

 

11     base() : m_j(0),m_i(m_j){} 

 

12     int get_i() {return m_i;} 

 

13     int get_j() {return m_j;} 

 

14 }; 

 

15   

 

16 int main () 

 

17 { 

 

18     base obj(98); 

 

19     cout << obj.get_i() <<endl<< obj.get_j() <<endl; 

 

20     return 0; 

 

21 }

 

解析:本題想得到的結果是“98,98”。但是成員變量的聲明是先m_i ,然後是m_j;初始化列表的初始化變量順序是根據成員變量的聲明順序來執行的,因此,先初始化m_i,但此時m_j 還未初始化,m_i 會被賦予一個隨機值。改變一下成員變量的聲明順序可以得到預想的結果。

 

答案:

 

輸出結果第一個為隨機數,第二個是98。

 

 

4、下面這個類聲明正確嗎?為什麼?

1 class A  

 

2 { 

 

3     const int Size = 0; 

 

4 };

 

解析:這道程序題存在著成員變量問題。常量必須在構造函數的初始化列表裡初始化或者將其設置成static。

 

答案:

 

正確的程序如下:

 

 

1 class A 

 

2 { 

 

3     A() 

 

4     { 

 

5         const int Size = 1; 

 

6     } 

 

7 };

 

 

或者:

 

1 class A 

 

2 { 

 

3     static const int Size = 1; 

 

4 };

 

 

5、析構函數可以為virtual 型,構造函數則不能,為什麼?

答案:

 

虛函數采用一種虛調用的辦法。虛調用是一種可以在只有部分信息的情況下工作的機制,特別允許我們調用一個只知道接口而不知道其准確對象類型的函數。但是如果要創建一個對象,你勢必要知道對象的准確類型,因此構造函數不能為virtual。

 

 

6、如果虛函數是非常有效的,我們是否可以把每個函數都聲明為虛函數?

答案:

 

不行,這是因為虛函數是有代價的:由於每個虛函數的對象都必須維護一個v 表,因此在使用虛函數的時候會產生一個系統開銷。如果僅是一個很小的類,且不行派生其他類,那麼根本沒必要使用虛函數。

 

 

7、請看下面一段程序:

01 #include<iostream> 

 

02 using namespace std; 

 

03   

 

04 class B 

 

05 { 

 

06 private: 

 

07     int data; 

 

08 public: 

 

09     B() 

 

10     { 

 

11         cout<<"defualt constructor"<<endl; 

 

12     } 

 

13   

 

14     ~B() 

 

15     { 

 

16         cout<<"destructed "<<endl; 

 

17     } 

 

18   

 

19     B( int i) : data(i) 

 

20     { 

 

21         cout<<"constructed by parameter"<<data<<endl; 

 

22     } 

 

23 }; 

 

24   

 

25 B Play( B b ) 

 

26 { 

 

27     return b; 

 

28 } 

 

29   

 

30 int main () 

 

31 { 

 

32     B temp = Play(5); 

 

33     return 0; 

 

34 }

 

問題:

 

       (1)該程序輸出結果是什麼?為什麼會有這樣的輸出?

 

      (2)B( int i ) : data( i ),這種用法的專業術語叫什麼?

 

      (3)Play( 5 ),形參類型是類,而5是個常量,這樣寫合法嗎?為什麼?

 

答案:

 

(1)輸出結果如下:

 

1 constructed by parameter//在Play(5)處,5通過隱含的類型轉換調用了B::B( int i ) 

 

2        destructed          //Play(5) 返回時,參數的析構函數被調用 

 

3        destructed           //temp的析構函數被調用;temp的構造函數調用的是編譯器生存的拷貝構造函數

 

(2)待參數的構造函數,冒號後面的是成員變量初始化列表(member initialization list)

 

(3)合法。單個參數的構造函數如果不添加explicit關鍵字,會定義一個隱含的類型轉換;添加explicit關鍵字會消除這種隱含轉換。

 

8、編寫類String 的構造函數、析構函數和賦值函數。

      已知類String 的原型為:

 

01 class String 

 

02 { 

 

03 public: 

 

04     String(const char *str = NULL);           //普通構造函數 

 

05     String(const String &other);              //拷貝構造函數 

 

06     ~String(void);                            //析構函數 

 

07     String & operate =(const String &other);  //賦值函數 

 

08 private: 

 

09     char *m_data;                             //用於保存字符串 

 

10 };

 

答案:

 

1、String 的析構函數:

 

1 String::~String(void) 

 

2 { 

 

3     delete [] m_data; 

 

4 }

 

2、String 的構造函數:

 

01 String::String(const char *str) 

 

02 { 

 

03     if(NULL==str) 

 

04     { 

 

05         m_data = new char[1]; 

 

06         *m_data = '\0'; 

 

07     } 

 

08     else

 

09     { 

 

10         int length = strlen(str); 

 

11         m_data = new char[length+1]; 

 

12         strcpy(m_data,str); 

 

13     } 

 

14 }

 

3、String的拷貝構造函數:

 

1 String::String(const String &other) 

 

2 { 

 

3     int length = strlen(other.m_data); 

 

4     m_data = new char[length+1]; 

 

5     strcpy(m_data,other.m_data); 

 

6 }

 

4、String的賦值函數:

 

01 String & String::operate =(const String &other) 

 

02 { 

 

03     if(this== &other) //檢查自復制 

 

04     { 

 

05         return *this; 

 

06     } 

 

07     delete [] m_data; //釋放原有的內存資源 

 

08     int length=strlen(other.m_data); //分配新內存資源,並復制內容 

 

09     m_data = new char[length+1]; 

 

10     strcpy(m_data,other.m_data); 

 

11     return *this;     //返回本對象的引用 

 

12 }

 

 

 

 

9、重載與覆蓋有什麼不同?

答案:

 

     虛函數總是在派生類中被改寫,這種改寫被稱為“override”(覆蓋)。

 

     override 是指派生類重寫基類的虛函數,重寫的函數必須有一致的參數表和返回值。Override這個單詞好像一直沒什麼合適的中文詞匯來對應。有些人譯為“覆蓋”,還貼切一些。

 

     overload約定成俗地被翻譯為“重載”,是指編寫一個與自己已有函數同名但是參數表不同的函數。例如一個函數既可以接受整型數作為參數,也可以接收浮點數作為參數。重載不是一種面向對象的編程,而是一種語法規則,重載與多態沒什麼直接關系。

 

作者:IT笨笨

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved