Golang - 關於 proto 檔案的一點小思考
面向物件
面向物件是把資料及對資料的操作方法放在一起,作為一個相互依存的整體,即物件。對同類物件抽象出其共性,即類,類中的大多數資料,只能被本類的方法進行處理。類通過一些簡單的外部介面與外界發生關係,物件與物件之間通過訊息進行通訊。
//int a;
//類 物件
基本特徵
面向物件方法首先對需求進行合理分層,然後構建相對獨立的業務模組,最後通過整合各模組,達到高內聚、低耦合的效果,從而滿足客戶要求。
具體而言,它有3個基本特徵:封裝、繼承和多型。
(1)封裝是指將客觀事物抽象成類,每個類對自身的資料和方法實行保護。類可以把自己的資料和方法只讓可信的類或物件操作,對不可信的進行隱藏。
(2)繼承可以使用現有類的所有功能,而不需要重新編寫原來的類,它的目的是為了進行程式碼複用和支援多型。它一般有3種形式:實現繼承、可視繼承、介面繼承。其中,實現繼承是指使用基類的屬性和方法而無需額外編碼的能力;可視繼承是指子窗體使用父窗體的外觀和實現程式碼;介面繼承僅使用屬性和方法,實現滯後到子類實現。
(3)多型是指同一個實體同時具有多種形式,它主要體現在類的繼承體系中,簡單地說,就是允許將子類型別的指標賦值給父類型別的指標,然後父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。
繼承與派生:
繼承與派生是同一個過程從不同的角度看:
保持已有類的特性而構成新類的過程稱為繼承
在已有類的基礎上新增自己的特性而產生新類的過程稱為派生
一個子類繼承父類時,可按照 public、private和protected 方式繼承父類,每種繼承方式的區別如下:
1) public繼承方式
- 基類中所有public成員在派生類中為public屬性;
- 基類中所有protected成員在派生類中為protected屬性;
- 基類中所有private成員在派生類中不可訪問。
2) protected繼承方式
- 基類中的所有public成員在派生類中為protected屬性;
- 基類中的所有protected成員在派生類中為protected屬性;
- 基類中的所有private成員在派生類中仍然不可訪問。
3) private繼承方式
- 基類中的所有public成員在派生類中均為private屬性;
- 基類中的所有protected成員在派生類中均為private屬性;
- 基類中的所有private成員在派生類中均不可訪問。
不管哪種繼承方式,父類的私有成員都不可以訪問,只有間接的(通過函式)通過公有成員才能獲取到私有成員的值。
派生類物件僅當 public 派生時,對基類中的 public 成員有可訪問/可修改的許可權,其他都為不可訪問/不可修改。
#include <iostream>
#include <String>
using namespace std;
// 基類
class student
{
public:
string name;
protected:
int age;
private:
char sex;
public:
void showStu()
{
cout << this->name << endl; // 1、在本類能夠訪問類的公有資料成員
cout << this->age << endl; // 1、在本類能夠訪問類的保護資料成員
cout << this->sex << endl; // 1、在本類能夠訪問類的私有資料成員
}
};
// 派生類 - public繼承
class public_Sub : public student
{
public:
void show()
{
cout << this->name << endl; // 2、public繼承,在派生類中能夠訪問基類的公有資料成員
cout << this->age << endl; // 2、public繼承,在派生類中能夠訪問基類的保護資料成員
//cout << this->sex << endl; // error:2、在c類中不能訪問基類的私有資料成員
}
};
// 派生類 - protected繼承
class protected_Sub : protected student
{
public:
void show()
{
cout << this->name << endl; // 3、protected繼承,在派生類中能夠訪問基類的公有資料成員
cout << this->age << endl; // 3、protected繼承,在派生類中能夠訪問基類的保護資料成員
//cout << this->sex << endl; // error:3、在派生類中不能訪問基類的私有資料成員
}
};
// 派生類 - private繼承
class private_Sub : private student
{
public:
void show()
{
cout << this->name << endl; // 4、private繼承,在派生類中能夠訪問基類的公有資料成員
cout << this->age << endl; // 4、private繼承,在派生類中能夠訪問基類的保護資料成員 【即使是private繼承】
//cout << this->sex << endl; // error:4、在派生類中不能訪問基類的私有資料成員
}
};
int main()
{
student stu;
cout << stu.name << endl; // 5、在類外可以訪問類的公有資料成員
//cout << stu.age << endl; // error,5、在類外不能訪問類的保護資料成員
//cout << stu.sex << endl; // error,5、在類外不能訪問類的私有資料成員
return 0;
}
虛擬函式:
指向基類的指標在操作它的多型類物件時,可以根據指向的不同類物件呼叫其相應的函式,這個函式就是虛擬函式。
虛擬函式的作用:在基類定義了虛擬函式後,可以在派生類中對虛擬函式進行重新定義,並且可以通過基類指標或引用,在程式的執行階段動態地選擇呼叫基類和不同派生類中的同名函式。(如果在派生類中沒有對虛擬函式重新定義,則它繼承其基類的虛擬函式。)
什麼是多型性?
多型意指 “一個介面,多種實現”。一句話概括就是:
在基類的函式前加上virtual關鍵字,在派生類中重寫該函式,執行時將會根據物件的實際型別來呼叫相應的函式。如果物件型別是派生類,就呼叫派生類的函式;如果物件型別是基類,就呼叫基類的函式,執行時繫結(動態繫結)。
(基類虛擬函式->子類覆蓋->基類指標指向子類物件)
原理?
編譯器為每個含有虛擬函式的類維護有一個虛擬函式表,而每個物件擁有一個虛指標(首地址儲存),指向虛擬函式表,物件間共有虛表(vtable)。
虛表可繼承,子類繼承基類虛表後,虛表與父類虛表完全相同(地址不同),只是物件的虛指標指向了本類的虛表。
虛擬函式指標指向各自的虛表,虛表地址指向各個函式,當父類被繼承時,重寫函式時子類的虛指標指向的虛表地址與父類相同,執行時會根據物件更新地址,呼叫派生類函式。
其它沒有被繼承的仍然與父類虛指標指向地址相同 。如果不加virtual關鍵字,則仍然呼叫父類函式。
#include <iostream>
using namespace std;
//int a;
//類 物件
class tran {
public:
virtual void fun() {
cout << 3 << endl;
}
virtual void fun2() {
cout << 33 << endl;
}
virtual void fun3() {
cout << 333 << endl;
}
int x;
};
class plane : public tran {
public:
void fun() {
cout << 7 << endl;
}
int y;
};
void add(int a, int b) {
cout << a + b << endl;
}
int main() {
void(*pp)(int, int);
pp= add;
pp(1, 2);
typedef void(*tp)(void);
tran a; //3
plane b; //7
tran* p;
cout << sizeof(a) << endl << sizeof(b) << endl;
p = &a;
p->fun();
p = &b;
p->fun();
tp** p1 = (tp**)&a;
cout << p1[0][0] << '\t' << p1[0][1] << '\t' << p1[0][2] << endl;
p1 = (tp**)&b;
cout << p1[0][0] << '\t' << p1[0][1] << '\t' << p1[0][2] << endl;
}
//類 物件
C++中的 struct與class的區別是什麼?
具體而言,在 C++ 中,class 和 struct 做型別定義時只有兩點區別:
(1)預設繼承許可權不同。class 繼承預設是 private 繼承,而 struct 繼承預設是 public 繼承;
(2)class 還用於定義模板引數,就像 typename,但關鍵字 struct 不用於定義模板引數。