程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> c++封裝、繼承和多態

c++封裝、繼承和多態

編輯:關於C語言

封裝(encapsulation)封裝就是將抽象得到的數據和行為或功能)相結合,形成一個有機的整體,也就是將數據與操作數據的源代碼進行有機的結合,形成“類”,其中數據和函數都是類的成員。封裝的目的是增強安全性和簡化編程,使用者不必了解具體的實現細節,而只是要通過 外部接口,一特定的訪問權限來使用類的成員。通過封裝使一部分成員充當類與外部的接口,而將其他的成員隱蔽起來,這樣就達到了對成員訪問權限的合理控制,使不同類之間的相互影響減少到最低限度,進而增強數據的安全性和簡化程序的編寫工作。


繼承:繼承是面向對象軟件技術當中的一個概念。如果一個類B繼承自另一個類A,就把這個B稱為A的子類,而把A稱為B的父類。繼承可以使得子類具有父類的各種屬性和方法,而不需要再次編寫相同的代碼。在令子類繼承父類的同時,可以重新定義某些屬性,並重寫某些方法,即覆蓋父類的原有屬性和方法,使其獲得與父類不同的功能。


多態Polymorphisn):多態性是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說:允許將子類類型的指針賦值給父類類型的指針。多態性在C++中都是通過虛函數Virtual Function)實現的。虛函數就是允許被其子類重新定義的成員函數。而子類重新定義父類虛函數的做法,稱為“覆蓋”或者稱為“重寫”override)。



接下來以示例進行講解:

繼承:

class BaseClass{
public:
    int a;
    void test1();
    virtual void printFunc(){
    cout<<"This is BaseClass."<<endl;
    }
protected:
    int b;
    void test2();
private:
    int c;
};
class DerivedClassA : public BaseClass{
public:
    void printFunc(){
    cout<<"This is DerivedClassA."<<endl;
    }
    void testA(){
       cout<<a<<endl
       <<b<<endl
       <<c<<endl;//報錯
    }
private:
    int d;
};

訪問控制和繼承權限

訪問控制:

在基類中,public和private標號具有普通含義:用戶代碼可以訪問類的public成員而不能訪問private成員,private成員只能由基類的成員和友元訪問。派生類對基類的public和private成員的訪問權限與程序中任意其他部分一樣:它可以訪問public成員而不能訪問private成員。有時作為基類的類具有一些成員,它希望允許派生類訪問但仍禁止其他用戶訪問這些成員。對於這樣的成員應使用受保護的訪問標號。protected成員可以被派生類對象訪問但不能被該類型的普通用戶訪問。

繼承權限:

公用繼承:基類成員保持自己的訪問級別,基類的public成員為派生類的 public成員,基類的protected成員為派生類的protected成員。

受保護繼承:基類的public和protected成員在派生類中為protected成員。

私有繼承:基類的的所有成員在派生類中為private成員。


上述例子中,在派生類中使用基類的數據成員a和b都沒有問題,但是使用c就會報錯。


多態:

C++ 中的函數調用默認不使用動態綁定。要觸發動態綁定,滿足兩個條件:第一,只有指定為虛函數的成員函數才能進行動態綁定,成員函數默認為非虛函數,非虛函數不進行動態綁定;第二,必須通過基類類型的引用或指針進行函數調用。要理解這一要求,需要理解在使用繼承層次中某一類型的對象的引用或指針時會發生什麼。

派生類中對於虛函數的重新定義不需要加virtual關鍵字,只要基類中有就行。

現在再定義一個派生類:

class DerivedClassB : public BaseClass{
public :
    void printFunc(){
    cout<<"This is DerivedClassB."<<endl;
    }
};


測試示例:

void main() {
    BaseClass *b1,*b2,*b3;
    BaseClass bc;
    DerivedClassA dcA;
    DerivedClassB dcB;
    b1 = &bc;
    b2 = &dcA;
    b3 = &dcB;
    b1->printFunc(); //調用基類的方法
    b2->printFunc();  //調用派生類A的方法
    b3->printFunc();  //調用派生類B的方法
}


友元關系與繼承:


友元可以訪問類的 private和protected數據。友元關系不能繼承。基類的友元對派生類的成員沒有特殊訪問權限。如果基類被授予友元關系,則只有基類具有特殊訪問權限,該基類的派生類不能訪問授予友元關系的類。


class Base {
friend class Frnd;
protected:
int i;
};
class D1 : public Base {
protected:
int j;
};
class Frnd {
public:
int mem(Base b) { return b.i; }
int mem(D1 d) { return d.i; } // 報錯
inherit
};
class D2 : public Frnd {
public:
int mem(Base b) { return b.i; } // 報錯
inherit
};


屏蔽與重載

如果派生類重定義了重載成員,則通過派生類型只能訪問派生類中重定義的那些成員。

如果派生類想通過自身類型使用的重載版本,則派生類必須要麼重定義所有重載版本,要麼一個也不重定義。

有時類需要僅僅重定義一個重載集中某些版本的行為,並且想要繼承其他版本的含義,在這種情況下,為了重定義需要特化的某個版本而不得不重定義每一個基類版本,可能會令人厭煩。

派生類不用重定義所繼承的每一個基類版本,它可以為重載成員提供 using

聲明。一個 using 聲明只能指定一個名字,不能指定形參表,因此,為基類成員函數名稱而作的 using 聲明將該函數的所有重載實例加到派生類的作用域。將所有名字加入作用域之後,派生類只需要重定義本類型確實必須定義的那些函數,對其他版本可以使用繼承的定義。

class BaseClass{
public:
    void test1(){
        cout<<"BaseTest1"<<endl;
    }
    virtual void printFunc(){
    cout<<"This is BaseClass."<<endl;
    }
private:
    int a;
};
class DerivedClassA : public BaseClass{
public:
    void printFunc(){
    cout<<"This is DerivedClassA."<<endl;
    }
    void test1(int t){
    cout<<"DerivedClassATest1"<<endl;
    }
private:
    int b;
};
void main() {
    BaseClass bc;
    DerivedClassA dcA;
    bc.test1();
    dcA.test1(1);
    dcA.test1();  //報錯,被屏蔽了
    dcA.BaseClass::test1();
}

   通過多態,可實現基類調用被屏蔽的虛函數。使用基類的指針來指向派生類的對象。





本文出自 “我的學習筆記” 博客,請務必保留此出處http://6924918.blog.51cto.com/6914918/1279707

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved