c++的三大特性
c++有三大特性:封裝、繼承和多態。
首先,我們談談c++的封裝,在學習c語言的時候我們都知道,在c語言中我們可以使用struct結構體來將數據存放起來,上節我們說到c語言的一切語法適用於c++,所以c++自然也可以用同樣的方法存放數據,如下:
#include <iostream> using namespace std; struct S{ int a, b; }; void f(const S& s){ //以引用的方式傳遞地址 cout << s.a << " " << s.b << " "; } int main(){ S s = {1, 2}; //定義一個S類,並賦值 f(s); //通過向函數f傳遞s的地址,以輸出s中的兩個屬性 S* z = &s; //定義一個指向s的指針z z->a = 3; //通過指針間接改變s中屬性e1的值,注意,針對指針必須使用“->”符號,用來調用結構體中的成員 (*z).b = 4; //通過指針指向的地址直接改變s中的屬性e2的值,這里則要用"."調用,因為此處是*z f(s); //再次輸出 }
但是在這樣的結構體中的數據會存在被函數調用或修改造成數據泄露的情況,所以在c++中提供了一些關鍵詞來保護數據的訪問權限--public、private、pretected。
public(共有):在這一關鍵詞之后的數據(屬性或方法)均為公共的,在結構體外的任何函數都可對其訪問或修改
private(私有):在這一關鍵詞之后的數據(屬性或者方法)均為對象私有的,只能在結構體內部進行修改或訪問,其他函數或結構體沒有訪問權限。
pretected(保護的):在這一關鍵詞之后的數據均為受保護的類型,只有在該類或由該類派生出來的類中才有訪問權限。例如:
#include <iostream> #include <cmath> #include <iomanip> using namespace std; struct Complex{ private: //關鍵詞private修飾,表示下面的re和im為結構體Complex的私有成員,只能在結構體中被訪問或修改 double re; double im; public: //關鍵詞private修飾,表示下面的方法(value,amount,getReal,getImag)為公共成員,不僅能在能在結構體中被訪問或修改,也可在main函數中被調用 void value(double r, double i){ re = r; im = i; } double amount(){ return sqrt(re * re + im * im); } double getReal(){ return re; } double getImag(){ return im; } }; int main(){ Complex z; z.re = 3; //產生編譯錯誤 z.im = 4; //產生編譯錯誤,此處re和im為結構體Complex的私有成員,在main函數中無訪問和修改權限 z.value(3, 4); //此處合法,方法value在結構體Complex,其擁有訪問和修改im和re的權限,而value被關鍵詞public所修飾,在main函數中可以訪問或調用 cout << z.re << " + " << z.im << "j"; //產生編譯錯誤 cout << z.getReal() << " + " << z.getImag() << "j"; //合法 cout << endl; cout << "the amount of this complex number is: " << sqrt(z.re * z.re + z.im * z.im); //產生編譯錯誤 cout << "the amount of this complex number is: " << z.amount(); //合法
除了struct,c++還提供了一個名叫類的關鍵詞(class),在class中,所有的屬性和方法,如果沒有特別聲明,則均視為private。
接下來我們說說c++的繼承,繼承是面向對象程序設計中使代碼可以復用的重要手段,它允許程序員在原有類特性的基礎上進行擴展增加功能。這樣產生的新的類叫派生類。
在c++中繼承的格式為:派生類名字 : 繼承權限 父類名字,不同的繼承方式有不同的繼承權限,
在C++語言中,一個派生類可以從一個基類派生,也可以從多個基類派生。從一個基類派生的繼承稱為單繼承;從多個基類派生的繼承稱為多繼承。派生類一般可以擁有基類的所有變量和函數(除了構造函數和析構函數的成員),並且可以在派生類中重寫基類的方法和變量,當然這會受到繼承權限的影響。並且派生類可以擁有基類沒有的方法與變量,可以說派生類是一種特殊的基類。以下便是繼承方式對子類對外訪問屬性影響的代碼
#include <cstdlib> #include <iostream> using namespace std; class A { private: int a; protected: int b; public: int c; A() { a = 0; b = 0; c = 0; } void set(int a, int b, int c) { this->a = a; this->b = b; this->c = c; } }; class B : public A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b; cout<<"c = "<<endl; } }; class C : protected A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b; cout<<"c = "<<endl; } }; class D : private A { public: void print() { //cout<<"a = "<<a; //err cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl; } }; int main_01(int argc, char *argv[]) { A aa; B bb; C cc; D dd; aa.c = 100; //ok bb.c = 100; //ok //cc.c = 100; //err 類的外部是什么含義 //dd.c = 100; //err aa.set(1, 2, 3); bb.set(10, 20, 30); //cc.set(40, 50, 60); //ee //dd.set(70, 80, 90); //ee bb.print(); cc.print(); dd.print(); system("pause"); return 0; }
繼承就簡單說到這里,最后我們談談c++的多態性,實現c++多態的關鍵在於虛函數,即在函數聲明的前面加上virtual關鍵字,在派生類中重寫該函數,運行時將會根據對象的實際類型來調用相應的函數。如果對象類型是派生類,就調用派生類的函數;如果對象類型是基類,就調用基類的函數。
1:用virtual關鍵字申明的函數叫做虛函數,虛函數肯定是類的成員函數。
2:存在虛函數的類都有一個一維的虛函數表叫做虛表,類的對象有一個指向虛表開始的虛指針。虛表是和類對應的,虛表指針是和對象對應的。
3:多態性是一個接口多種實現,是面向對象的核心,分為類的多態性和函數的多態性。
4:多態用虛函數來實現,結合動態綁定.
5:純虛函數是虛函數再加上 = 0;
6:抽象類是指包括至少一個純虛函數的類。
純虛函數:virtual void fun()=0;即抽象類!必須在子類實現這個函數,即先有名稱,沒有內容,在派生類實現內容。下面就是使用虛函數與非虛函數的對比
class Base { public: virtual void Funtest1(int i) { cout << "Base::Funtest1()" << endl; } void Funtest2(int i) { cout << "Base::Funtest2()" << endl; } }; class Drived :public Base { virtual void Funtest1(int i) { cout << "Drived::Fubtest1()" << endl; } virtual void Funtest2(int i) { cout << "Drived::Fubtest2()" << endl; } void Funtest2(int i) { cout << "Drived::Fubtest2()" << endl; } }; void TestVirtual(Base& b) { b.Funtest1(1); b.Funtest2(2); } int main() { Base b; Drived d; TestVirtual(b); TestVirtual(d); return 0; }
而這個程序運行的結果為
在調用FuncTest2的時候我們看出來他並沒有給我們調用派生類的函數,因此我們可以得到動態多態的條件為基類中必須包含虛函數並且派生類中一定要對基類中的虛函數進行重寫,通過基類對象的指針或者引用調用虛函數。
好了今天的c++特性就介紹到這里!