本文轉載自我的博客:劉衝的博客
我有相當長的一段時間(數月)沒有更新文章了。
並不是我放棄了寫技術文章,而是因爲這段時間,我把精力主要放在了圖像智能算法的學習上了。去年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 則更適合封裝對象。