程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++基礎知識面試精選100題系列(1-10題)[C++ basics]

C++基礎知識面試精選100題系列(1-10題)[C++ basics]

編輯:C++入門知識

【原文鏈接】

http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-1-10.html

題目1

我們可以用static修飾一個類的成員函數,也可以用const修飾類的成員函數(寫在函數的最後表示不能修改成員變量,不是指寫在前面表示返回值為常量)。請問:能不能同時用static和const修飾類的成員函數?

分析

不可以。C++編譯器在實現const的成員函數的時候為了確保該函數不能修改類的實例的狀態,會在函數中添加一個隱式的參數const this*。但當一個成員為static的時候,該函數是沒有this指針的。我們也可以這樣理解:兩者的語意是矛盾的。static是針對類型,與類的實例沒有關系;而const是針對實例,確保函數不能修改實例的狀態。因此不能同時用它們。


題目2

運行下面的代碼,輸出是什麼?

 C++ Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23   class A
{
};

class B
{
public:
    B() {}
    ~B() {}
};

class C
{
public:
    C() {}
    virtual ~C() {}
};

int _tmain(int argc, _TCHAR *argv[])
{
    printf("%d, %d, %d\n", sizeof(A), sizeof(B), sizeof(C));
    return 0;
}

分析

答案是1, 1, 4。

class A是一個空類型,它的實例不包含任何信息,本來求sizeof應該是0。但當我們聲明該類型的實例的時候,它必須在內存中占有一定的空間,否則無法使用這些實例。至於占用多少內存,由編譯器決定。Visual Studio 2008中每個空類型的實例占用一個byte的空間。

class B在class A的基礎上添加了構造函數和析構函數。由於構造函數和析構函數的調用與類型的實例無關(調用它們只需要知道函數地址即可),在它的實例中不需要增加任何信息。所以sizeof(B)和sizeof(A)一樣,在Visual Studio 2008中都是1。

class C在class B的基礎上把析構函數標注為虛擬函數。C++的編譯器一旦發現一個類型中有虛擬函數,就會為該類型生成虛函數表,並在該類型的每一個實例中添加一個指向虛函數表的指針。在32位的機器上,一個指針占4個字節的空間,因此sizeof(C)是4。


 【題目3

運行下面中的代碼,得到的結果是什麼?

 C++ Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30   #include "stdafx.h"

class A
{
private:
    int m_value;

public:
    A(int value)
    {
        m_value = value;
    }
    void Print1()
    {
        printf("hello world");
    }
    void Print2()
    {
        printf("%d", m_value);
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = NULL;
    pA->Print1(); // "hello world"
    pA->Print2(); // ERROR

    return 0;
}

分析

答案是Print1調用正常,打印出hello world,但運行至Print2時,程序崩潰。調用Print1時,並不需要pA的地址,因為Print1的函數地址是固定的。編譯器會給Print1傳入一個this指針,該指針為NULL,但在Print1中該this指針並沒有用到。只要程序運行時沒有訪問不該訪問的內存就不會出錯,因此運行正常。在運行print2時,需要this指針才能得到m_value的值。由於此時this指針為NULL,因此程序崩潰了。


 【題目4

運行下面中的代碼,得到的結果是什麼?

 C++ Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28   class A
{
private:
    int m_value;

public:
    A(int value)
    {
        m_value = value;
    }
    void Print1()
    {
        printf("hello world");
    }
    virtual void Print2()
    {
        printf("hello world");
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = NULL;
    pA->Print1();
    pA->Print2();

    return 0;
}

【分析】

答案是Print1調用正常,打印出hello world,但運行至Print2時,程序崩潰。Print1的調用情況和上面的題目一樣,不在贅述。由於Print2是虛函數。C++調用虛函數的時候,要根據實例(即this指針指向的實例)中虛函數表指針得到虛函數表,再從虛函數表中找到函數的地址。由於這一步需要訪問實例的地址(即this指針),而此時this指針為空指針,因此導致內存訪問出錯。


 【題目5

靜態成員函數能不能同時也是虛函數?

【分析】

答案是不能。調用靜態成員函數不要實例,但調用虛函數需要從一個實例中獲取指向虛函數表的指針以得到函數的地址,因此調用虛函數需要一個實例。兩者相互矛盾。


 題目6

運行下列C++代碼,輸出什麼?

 C++ Code  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"

struct Point3D
{
    int x;
    int y;
    int z;
};

int _tmain(int argc, _TCHAR *argv[])
{
    Point3D *pPoint = NULL;
    int offset = (int)(&pPoint->z);

    printf("%d", offset); // 8
    return 0;
}
/*
+       pPoint  0x00000000 {x=??? y=??? z=??? } Point3D *
+       &pPoint->x  0x00000000  int *
+       &pPoint->y  0x00000004  int *
+       &pPoint->z  0x00000008  int *
*/

【分析】

輸出8。&(pPoint->z)的語意是求pPoint中變量z的地址(pPoint的地址0加z的偏移量8),並不需要訪問pPoint指向的內存。只要不訪問非法的內存,程序就不會出錯。


 題目7

運行下列C++代碼,輸出什麼?

 C++ Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56   #include "stdafx.h"

class A
{
public:
    A()
    {
        Print();
    }
    ~A()
    {
        printf("A is erased.\n");
    }
    virtual void Print()
    {
        printf("A is constructed.\n");
    }
};

class B: public A
{
public:
    B()
    {
        Print();
    }
    ~B()
    {
        printf("B is erased.\n");
    }
    virtual void Print()
    {
        printf("B is constructed.\n");
    }
};

int _tmain(int argc, _TCHAR *argv[])
{
    A *pA = new B();
    delete pA;

    B *pB = new B();
    delete pB;

    return 0;
}
/*
A is constructed.
B is constructed.
A is erased.

A is constructed.
B is constructed.
B is erased.
A is erased.
*/

【分析】

輸出結果如上所示。


【題目8】

運行下列C#代碼,輸出是什麼?

 C# Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14   namespace ChangesOnString
{
    class Program
    {
        static void Main(string[] args)
        {
            String str = "hello";
            str.ToUpper();
            str.Insert(0, " WORLD");

            Console.WriteLine(str);
        }
    }
}

【分析】

輸出是hello。由於在.NET中,String有一個非常特殊的性質:String的實例的狀態不能被改變。如果String的成員函數會修改實例的狀態,將會返回一個新的String實例。改動只會出現在返回值中,而不會修改原來的實例。所以本題中輸出仍然是原來的字符串值hello。如果試圖改變String的內容,改變之後的值可以通過返回值拿到。用StringBuilder是更好的選擇,特別是要連續多次修改的時候。如果用String連續多次修改,每一次修改都會產生一個臨時對象,開銷太大。


【題目9】

在C++和C#中,struct和class有什麼不同?

【分析】

在C++中,如果沒有標明函數或者變量是的訪問權限級別,在struct中,是public的;而在class中,是private的。

在C#中,如果沒有標明函數或者變量的訪問權限級別,struct和class中都是private的。

struct和class的區別是:struct定義值類型,其實例在棧上分配內存;class定義引用類型,其實例在堆上分配內存。


 【題目10】

運行下圖中的C#代碼,輸出是什麼?

 C# Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34   namespace StaticConstructor
{
    class A
    {
        public A(string text)
        {
            Console.WriteLine(text);
        }
    }

    class B
    {
        static A a1 = new A("a1");
        A a2 = new A("a2");

        static B()
        {
            a1 = new A("a3");
        }

        public B()
        {
            a2 = new A("a4");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
        }
    }
}

【分析】

打印出四行,分別是a1、a3、a2、a4。

在調用類型B的代碼之前先執行B的靜態構造函數。靜態函數先初始化類型的靜態變量,再執行靜態函數內的語句。因此先打印a1再打印a3。接下來執行B b = new B(),即調用B的普通構造函數。構造函數先初始化成員變量,在執行函數體內的語句,因此先後打印出a2、a4。

【參考】

http://zhedahht.blog.163.com/blog/static/254111742011012111557832/

【原文鏈接】

http://www.cnblogs.com/hellogiser/p/100-interview-questions-of-cplusplus-basics-1-10.html

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