面向對象的三個基本特征
面向對象的三個基本特征是:封裝、繼承、多态。其中,封裝可以隐藏實作細節,使得代碼子產品化;繼承可以擴充已存在的代碼子產品(類);它們的目的都是為了——代碼重用。而多态則是為了實作另一個目的——接口重用!
封裝
封裝可以隐藏實作細節,使得代碼子產品化;封裝是把過程和資料包圍起來,對資料的通路隻能通過已定義的界面。面向對象計算始于這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的對象,這些對象通過一個受保護的接口通路其他對象。在面向對象程式設計上可了解為:把客觀事物封裝成抽象的類,并且類可以把自己的資料和方法隻讓可信的類或者對象操作,對不可信的進行資訊隐藏。
繼承
繼承是指這樣一種能力:它可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴充。其繼承的過程,就是從一般到特殊的過程。
通過繼承建立的新類稱為“子類”或“派生類”。被繼承的類稱為“基類”、“父類”或“超類”。要實作繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實作。在某些OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類隻能有一個基類,要實作多重繼承,可以通過多級繼承來實作。
多态
多态性(polymorphisn)是允許你将父對象設定成為和一個或更多的他的子對象相等的技術,指派之後,父對象就可以根據目前指派給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許将子類類型的指針指派給父類類型的指針。
繼承
繼承性是面向對象程式設計的第二大特性,它允許在既有類的基礎上建立新類,新類可以繼承既有類的資料成員和成員函數,可以添加自己特有的資料成員和成員函數,還可以對既有類中的成員函數重新定義。利用類的繼承和派生實作了更高層次的代碼可重用性,符合現代軟體開發的思想。
C++語言同時支援單一繼承和多重繼承。單一繼承是指派生類隻從一個基類繼承而來;相應的,多重繼承指派生類同時從兩個或更多的基類繼承而來。java隻支援單一繼承。
派生類:
派生類的定義格式如下:
class <派生類名>:[繼承方式]<基類名1>
[,[繼承方式]<基類名2>,...,[繼承方式]<基類名n>]
{
<派生類新增的資料成員和成員函數定義>
};
說明:
(1)定義派生類關鍵字可以是class或者是struct,兩者差別是:用class定義派生類,預設的繼承方式是private,用struct定義派生類,預設的繼承方式為public。新增加的成員預設屬性也是class對應private屬性,struct對應public屬性。
(2)基類不能被派生類繼承的兩類函數是構造函數和析構函數。(以上借鑒:https://www.cnblogs.com/Rosanna/p/3331578.html)
繼承方式
基類中不同的通路限定符下的成員以不同的繼承方式繼承 在派生類中的方向
類和類之間的關系
組合:a part of 私有 has a
繼承:a kind of 共有/保護 is a
代理:
派生類調用構造和析構方式
先調用基類構造函數,構造基類部分成員變量,再調用派生類構造函數構造派生類部分的成員變量。2.基類部分成員的初始化方式在派生類構造函數的初始化清單中指定。3.若基類中還有成員對象,則先調用成員對象的構造函數,再調用基類構造函數,最後是派生類構造函數。析構順序和構造順序相反。
class Base
{
public:
Base(int a)
{
ma = a;
cout<<"Base::base()"<<endl;
}
~Base()
{
cout<<"Base::~base()"<<endl;
}
private:
int ma;
};
class Derive : public Base
{
public:
Derive(int b):Base(b)
{
mb = b;
cout<<"Derive::derive()"<<endl;
}
~Derive()
{
cout<<"Derive::~derive()"<<endl;
}
private:
int mb;
};
int main()
{
Derive d(2);
return 0;
}
同名函數的關系
重載(overload) :是指同一可通路區内被聲明的幾個具有不同參數列(參數的類型,個數,順序不同)的同名函數,根據參數清單确定調用哪個函數,重載不關心函數傳回類型。
class A{
public:
void test(int i);
void test(double i);//overload
void test(int i, double j);//overload
void test(double i, int j);//overload
int test(int i); //錯誤,非重載。注意重載不關心函數傳回類型。
};
隐藏(overhide):是指派生類的函數屏蔽了與其同名的基類函數,注意隻要同名函數,不管參數清單是否相同,基類函數都會被隐藏
隐藏條件----1.繼承 不同作用域 2.同名函數
要不被隐藏就顯式的加作用域ok
class Base
{
public:
void fun(double ,int ){ cout << "Base::fun(double ,int )" << endl; }
};
class Derive : public Base
{
public:
void fun(int ){ cout << "Derive::fun(int )" << endl; }
};
int main()
{
Derive pd;
pd.fun(1);
Base *fd = &pd;
fd->fun(1.0,1);
//fd->fun(1);//error
system("pause");
return 0;
}
那句fd->fun(1); 錯誤原因--->“Base::fun”: 函數不接受 1 個參數
重寫(覆寫overwrite):是指派生類中存在重新定義的函數。其函數名,參數清單,傳回值類型,所有都必須同基類中被重寫的函數一緻。隻有函數體不同(花括号内),派生類調用時會調用派生類的重寫函數,不會調用被重寫函數。重寫的基類中被重寫的函數必須有virtual修飾。
class Base
{
public:
Base(int a) :ma(a)
{
std::cout << "Base::Base(int)" << std::endl;
}
virtual ~Base()
{
std::cout << "Base::~Base()" << std::endl;
}
virtual void Show()
{
std::cout << "Base::Show ==> ma:" << ma << std::endl;
}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int b) :Base(b), mb(b)
{
std::cout << "Derive::Derive(int)" << std::endl;
}
~Derive()
{
std::cout << "Derive::~Derive()" << std::endl;
}
void Show()
{
std::cout << "Derive::Show ==> mb:" << mb << std::endl;
}
private:
int mb;
};
int main()
{
Base* pb = new Derive(10);
pb->Show();
//delete pb;//pb->~Base() // call Base::~Base();
//pb->destor pb->~Derive() //
return 0;
}
基類Show函數被重寫!
Derive* pb = new Base(10);
這樣不對的!錯誤原因---->從基類型到派生類型的強制轉換需要 dynamic_cast 或 static_cast
虛函數
https://blog.csdn.net/haoel/article/details/1948051#commentBox大佬的
多态
靜多态和動多态的差別:
其實隻是差別什麼時間将函數實作和函數調用關聯起來,是在編譯期還是在運作期,即函數位址是在早綁定還是晚綁定的??
①靜多态是指在編譯期就可以确定函數的調用位址,并産生代碼,這就是靜态的,也就是說位址是早早綁定的,靜多态往往也被叫做靜态聯翩。
②動多态則是指函數調用的位址不能在編譯期間确定的,必須要在運作時才能确定,這就屬于晚綁定,動多态往往也被叫做動态聯翩。
詳細博文:https://blog.csdn.net/qq_39412582/article/details/81628254
https://www.cnblogs.com/cxq0017/p/6074247.html
https://blog.csdn.net/qq_36359022/article/details/81870219#commentBox
那些函數不能定義為虛函數?
經檢驗下面的幾個函數都不能定義為虛函數:
1)友元函數,它不是類的成員函數
2)全局函數
3)靜态成員函數,它沒有this指針
3)構造函數,拷貝構造函數,以及指派運算符重載(可以但是一般不建議作為虛函數)
虛析構
積累指針指向派生類對象時,最好把析構寫為虛析構,避免通過積累指針釋放派生類對象 派生類中自己的資源無法釋放
動多态的發生時機
- 指針調用虛函數
- 對象完整
多繼承
菱形繼承 虛繼承
https://www.cnblogs.com/fire909090/p/7085146.html
怎麼設計一個不能被繼承的類
- 類似單例模式設計
- 有緣 不能被繼承
友元函數:
- 友元關系不能被繼承。
- 友元關系是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的聲明。
- 友元關系不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明
詳細:https://blog.csdn.net/pursue_my_life/article/details/80466142