struct 關鍵字在 C++ 中與C語言不同,C++中struct和class有什麼區別?它們很像,C++爲什麼不刪除struct?

本文轉載自我的博客:劉衝的博客

我有相當長的一段時間(數月)沒有更新文章了。

並不是我放棄了寫技術文章,而是因爲這段時間,我把精力主要放在了圖像智能算法的學習上了。去年12月時,我對圖像智能算法還懵懵懂懂,做着 Linux 嵌入式應用程序開發,現在我已經正式入職到算法公司了,收入翻了一番,哈哈,不過累了好多。廢話就到這裏,我的轉行辛酸史,以後再詳談。

坦誠的說,就編程語言而言,因爲一直在做 Linux 嵌入式程序開發的緣故,我對C語言更加了解一點,讀者應該能夠發現,我之前的大部分文章都是關於C語言的。不過現在做算法,C++更加適合。C++和C語言雖然很像,但是在細節上還是有所區別的。今天閱讀前輩同事的代碼時,注意到了 struct 關鍵字,這個關鍵字在C++中做了不少擴展。本文將嘗試做下總結。

C語言與C++中的struct

struct關鍵字是C語言中非常重要的關鍵字,在實際的C語言程序開發中,struct 不僅可以用於封裝各種複雜的數據結構,還能夠實現一些開發技巧——比如輔助數組賦值、模擬類等等,這些我之前的文章都討論過。C++不僅保留了C語言中 struct 的功能,還做了不少擴展,具體的可以通過下面這個表說明:

. C語言 C++
成員函數 不能 可以
靜態成員 不能 可以
訪問控制屬性 等價public public/private/protected
可以繼承

請看下面這段C++代碼示例,我們首先使用 struct 定義了 S1,接着又定義了 S2,S2 繼承了 S1,因此我們可以在 test2 中使用 S1 中定義的成員 a、b。同時也可以看出,C++中的 struct 還可以定義成員函數,包括構造函數和析構函數。

#include <iostream>

using namespace std;

struct S1 {
    int    a;
    int    b;

    S1() {
		a = 1;
		b = 2;
    }

	void print_mem() {
		cout << "a = "<< a << ", b = "<<b <<endl;
	}
};

struct S2: S1 {
	int		c;
	~S2() {
		cout << "S2 exit, c = " << c << endl;
		cout << "a = "<< a << ", b = "<<b <<endl;
	}
};

int main()
{
	S1 test1;
	test1.print_mem();

	S2 test2;
	test2.a = 3;
	test2.b = 4;
	test2.c = 5;

	return 0;
}

編譯並執行上述C++代碼,不出意外地得到如下輸出:

$ g++ t1.cpp 
$ ./a.out 
a = 1, b = 2
S2 exit, c = 5
a = 3, b = 4

C++ 中的 struct 和 class 關鍵字

從上面的例子不難看出,C++中的 struct 除了像C語言那樣可以定義數據結構外,還可以像 class 關鍵字那樣定義成員函數。不過,二者是有區別的。

成員的默認訪問控制屬性

首先,struct 默認的訪問控制屬性是 public,而 class 默認的訪問控制屬性是 private,這一點可以通過下面這段C++代碼示例看出:

struct A {
    int a;
};
class B {
    int b;
};

A ta;
ta.a = 1; // 沒有問題

B tb;
tb.b = 2; // 編譯報錯

繼承的默認訪問控制屬性

類似的,在繼承的過程中,struct 和 class 關鍵字的默認訪問控制屬性也是有所區別的:struct 默認 public,class 默認 private,例如下面這段C++ 代碼:

struct A {
    int a;
};
struct B: A {
    int b;
};

B tb;
tb.a = 1; // 正常

這是沒有問題的,對象 tb 可以訪問由 A 繼承而來的成員 a。但是如果將 B 的 struct 改爲 class,也即:

struct A {
    int a;
};
class B: A {
    int b;
};

B tb;
tb.a = 1; // 編譯報錯

此時編譯就會報錯,提示“‘int A::a’ is inaccessible”,因爲 class 的默認繼承屬性爲 private。現在我們將 A 的 struct 修改爲 class,B 的 class 再改回 struct,會發現,對象 tb 依然能夠正常訪問成員 a:

class A {
public:
    int a;
};
struct B: A {
    int b;
};

B tb;
tb.a = 1; // 正常

應注意,這裏的討論重點是繼承的默認訪問控制屬性,因此我們將 A 中的 a 定義爲 public 的。

可以看出,當 class 和 struct 混合使用時,默認的訪問控制屬性由子類決定,而不是由基類決定。不過,依賴默認屬性不是特別清晰的寫法,在實際的C++程序開發中,更推薦的做法是指明繼承的方式:

class B: private A {
    ...
};
class B: public A {
    ...
};

定義模板

相較於C語言,C++還能夠定義模板函數,請看下面這段代碼示例:

template<typename T>                                                                                             void fun(T num) {
     cout << "num = " << num << endl;
} 
fun(1); // num = 1
fun(1.01); // num = 1.01

在一些開源工程中,我還發現過有使用 class 定義模板函數的,也即使用class替換typename關鍵字:

template<class T>                                                                                             void fun(T num) {
     cout << "num = " << num << endl;
} 

這種定義方式和上面使用typename的定義方式完全相同,但是 struct 就不能用於定義模板函數,如果讀者嘗試了,應該會得到編譯報錯的結果。

小結

本文先是討論了 struct 關鍵字在C語言和C++中的不同,不難發現,C++對 struct 關鍵字是做了不少擴充的,這些擴充讓 struct 看起來更像是 class 關鍵字。事實上,我認爲就單純C++來說,class 關鍵字是完全可以取代 struct 的,C++ 仍然保留着 struct 關鍵字,其中一個重要原因就是兼容C語言。既然保留了 struct 關鍵字,總不能讓它完全等價於 class,因此二者在一些細節上有區別,這些輕微的區別往往能夠針對不同的需求提供不同的方便:struct 更適合封裝數據結構,class 則更適合封裝對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章