国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C++】面向對象之多態(tài)

這篇具有很好參考價值的文章主要介紹了【C++】面向對象之多態(tài)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

文章內的所有調試都是在vs2022下進行的,

部分小細節(jié)可能因編譯器不同存在差異。

多態(tài)的定義和實現(xiàn)

概念引入

對于一個火車票售票系統(tǒng),

可能會有多重角色,

比如普通成人類、學生類、軍人類、兒童類等等…

這些類可能都是從某個基類派生出來的,

而且每個類都有一個基本需求,就是買票,

所以對于同一個購票函數(shù)BuyTicket()

當不同的類去調用它時它應該執(zhí)行不同的功能,

比如成人要全價賣票,學生可以半價買票,軍人得優(yōu)先買票…

所以怎樣滿足這一需求呢?

通過多態(tài)的機制。

所以多態(tài)其實就是不同繼承關系的類實例化出來的對象去調用同一函數(shù),

最終用同一個函數(shù)了執(zhí)行不同的動作

感覺其實有點兒函數(shù)重載的意味…


多態(tài)的構成條件

首先見一見多態(tài)是個什么情況。

這是一段代碼:

class Person
{
public:
    virtual void BuyTicket()
    { cout << "原價買票" << endl; }
};

class Student : public Person
{
public:
    virtual void BuyTicket()
    { cout << "半價買票" << endl; }
};

class Solider : public Person
{
public:
    virtual void BuyTicket()
    { cout << "優(yōu)先買票" << endl; }
};

void QueryPriority(Person* p)
{ p->BuyTicket(); }

int main()
{
    Person p;
    QueryPriority(&p);

    Student stu;
    QueryPriority(&stu);

    Solider solider;
    QueryPriority(&solider);

    return 0;
}

運行結果如下:

虛函數(shù)重寫

在講多態(tài)的構成條件之前要先引入一個虛函數(shù)的概念。

虛函數(shù)就是用virtual修飾的函數(shù),

在繼承一文中已經初步見識過virtual關鍵字了,

當時是用virtual進行虛擬繼承,

在菱形繼承中避免數(shù)據(jù)二義性和冗余問題,

這里是用來修飾函數(shù)使之成為虛函數(shù),

作為多態(tài)的構成條件之一。

所以構成多態(tài)的第一個條件是被調用的函數(shù)必須是虛函數(shù),

在上面的例子中被調用的函數(shù)是BuyTicket()函數(shù),

所以它要定義成虛函數(shù):

class Person
{
public:
    virtual void BuyTicket()
    { cout << "原價買票" << endl; }
};

這樣的話BuyTicket()函數(shù)會被繼承到派生類中,

我們當然可以不加virtual,

直接在派生類中重載BuyTicket()函數(shù),

此時派生類中就有了兩個BuyTicket()函數(shù),

一個是派生類中重載的,一個是基類的,

這兩個函數(shù)是構成隱藏關系的。

于是就有了數(shù)據(jù)冗余和二義性…

而我們只想保留一份函數(shù),

基類對象調用時執(zhí)行基類中定義的行為,

派生類對象調用時執(zhí)行派生類中定義的行為。

顯然重載是完成不了這個任務的,

所以取而代之的就是重寫

class Student : public Person
{
public:
    virtual void BuyTicket()
    { cout << "半價買票" << endl; }
};

class Solider : public Person
{
public:
    virtual void BuyTicket()
    { cout << "優(yōu)先買票" << endl; }
};

此前在基類和派生類中重名的成員變量或成員函數(shù)是構成隱藏/重定義關系的,

但那是對于普通函數(shù)而言,

滿足一定條件的虛函數(shù)則是會構成覆蓋/重寫關系,

意味著在派生類中只有這么一個函數(shù)存在,

繼承下來的基類的函數(shù)完全被覆蓋掉了。

上面說的滿足一定條件,

前提一定是虛函數(shù),

此外除了函數(shù)名相同,

函數(shù)的返回值類型和參數(shù)列表也要相同

但是返回值類型相同還有例外,

基類與派生類的虛函數(shù)返回值類型可以不相同,

但一定要是繼承關系中基類或派生類的指針或引用,

舉個簡單的例子:

class Student : public Person
{
public:
    virtual Student* BuyTicket()
    { cout << "半價買票" << endl; }
}

class Solider : public Person
{
public:
    virtual Solider* BuyTicket()
    { cout << "優(yōu)先買票" << endl; }
}

這種情況下仍然構成多態(tài),

(這么雞肋的寫法應該沒人用吧)…

以上就是構成多態(tài)的其一條件:

被調用的函數(shù)必須是虛函數(shù),且派生類必須對基類的虛函數(shù)進行重寫


通過基類的指針或者引用調用虛函數(shù)

諸如上面的多態(tài)調用:

Person p;
Person* ptr = &p;
ptr->BuyTicket();

Student stu;
ptr = &stu;
ptr->BuyTicket();

Solider solider;
ptr = &solider;
ptr->BuyTicket();

想要實現(xiàn)函數(shù)的多態(tài)調用,

首先函數(shù)一定是重寫過的虛函數(shù),

再就是要通過基類指針或者引用來調用。

至于為什么,在后面的多態(tài)原理細細闡述。

此前在繼承一文中提出過一個問題:

如果這么定義了一個對象(此處省略類的定義):

int main()
{
	A* p = new B;
    delete p;
    
    return 0;
}

此時運行結果如下:

【C++】面向對象之多態(tài)

此時只調用了A的析構,

對B的部分成員并沒有處理,

因此造成了內存泄漏!

那么現(xiàn)在就可以解決這個問題,

就是將析構函數(shù)定義成虛函數(shù)

在析構時會多態(tài)調用B類的析構函數(shù),

就不會發(fā)生內存泄漏了。

這里有一個細節(jié),

前面提到函數(shù)構成重寫的條件之一是函數(shù)名必須相同,

而析構函數(shù)顯然不符合這個條件,

但為什么又能實現(xiàn)重寫呢?

實際上編譯器偷偷對析構函數(shù)進行了處理,

統(tǒng)一將析構函數(shù)處理成同名函數(shù)。


override和final

C++對函數(shù)重寫的要求比較嚴格,

但是有些情況下由于疏忽,

可能會導致函數(shù)名字母次序寫反而無法構成重寫,

而這種錯誤在編譯期間是不會報出的,

只有在程序運行時沒有得到預期結果才來debug會得不償失,

因此,C++11提供了overridefinal兩個關鍵字,

可以幫助用戶檢測是否重寫。

final:修飾虛函數(shù),表示該虛函數(shù)不能再被重寫

class Person
{
public:
    virtual void BuyTicket() final
    {
        cout << "原價買票" << endl;
    }
};

class Student : public Person
{
public:
    virtual void BuyTicket()
    {
        cout << "半價買票" << endl;
    }
};

override: 檢查派生類虛函數(shù)是否重寫了基類某個虛函數(shù),如果沒有重寫編譯報錯

class Person
{
public:
    virtual void BuyTicket()
    {
        cout << "原價買票" << endl;
    }
};

class Student : public Person
{
public:
    virtual void BuyTickte() override
    {
        cout << "半價買票" << endl;
    }
};

上面故意錯把派生類中的函數(shù)名寫錯了。


抽象類

概念

在虛函數(shù)的后面寫上=0 ,

則這個函數(shù)為純虛函數(shù)。

包含純虛函數(shù)的類叫做抽象類(也叫接口類),

抽象類不能實例化出對象。

派生類繼承后也不能實例化出對象,

只有重寫純虛函數(shù),派生類才能實例化出對象。

純虛函數(shù)規(guī)范了派生類必須重寫,

另外純虛函數(shù)更體現(xiàn)出了接口繼承。

class Person
{
public:
    virtual void BuyTicket() = 0
    {
        cout << "原價買票" << endl;
    }
    
    void func()
    {}
};

實現(xiàn)繼承和接口繼承

普通函數(shù)的繼承是一種實現(xiàn)繼承,

派生類繼承了基類函數(shù),可以使用函數(shù),

繼承的是函數(shù)的實現(xiàn)。

虛函數(shù)的繼承是一種接口繼承,

派生類繼承的是基類虛函數(shù)的接口,

目的是為了重寫,達成多態(tài),

繼承的是接口。

所以如果不實現(xiàn)多態(tài),

不要把函數(shù)定義成虛函數(shù)。


虛函數(shù)表

64位地址太長,

所以為了方便觀察,

下面統(tǒng)一換成32位地址。

現(xiàn)在定義一個基類:

class Base
{
public:
    virtual void Func1()
    {
    	cout << "Func1()" << endl;
    }
private:
	int _b = 1;
};

然后定義一個Base對象,

那這個對象的對象模型是怎樣的呢?

相比于沒有虛函數(shù)的普通對象多了一個_vfptr

【C++】面向對象之多態(tài)

看樣子是一個數(shù)組,

數(shù)組元素都是指針,

那看來_vfptr是一個指針數(shù)組:

【C++】面向對象之多態(tài)

這里顯示它有一個元素,

這個元素存放的是Func1函數(shù)的地址。

多出來的這個_vfptr虛函數(shù)表指針

完整應該叫做visual function table pointer,

虛函數(shù)表我們一般簡稱為虛表,

注意和繼承中的虛基表的概念區(qū)分開,

它存放的其實就是虛函數(shù)的地址,

注意虛函數(shù)并不存放在這兒,

虛函數(shù)和普通函數(shù)一樣是存放在代碼段的。

所以一個含有虛函數(shù)的類中都至少都有一個虛表指針。


單繼承中的虛表

我們再進一步看在繼承中虛表是怎樣的,

在上面代碼的基礎上我們再寫點東西:

class Base
{
public:
	virtual void Func1()
	{ cout << "Base::Func1()" << endl; }
    
	virtual void Func2()
	{ cout << "Base::Func2()" << endl; }
    
	void Func3()
	{ cout << "Base::Func3()" << endl; }
    
private:
	int _b = 1;
};

class Derive : public Base
{
public:
	virtual void Func1()
	{ cout << "Derive::Func1()" << endl; }
    
	virtual void Func4()
	{ cout << "Derive::Func4()" << endl; }
private:
	int _d = 2;
};

此時再看一下它們的對象模型有什么變化:

【C++】面向對象之多態(tài)

基類對象的結構還是原來那樣,

只不過虛表中多了一個指向Func2函數(shù)的指針,

Func3并不在這兒,因為它不是虛函數(shù)。

派生類繼承了基類的虛表,

但是存的指針有些變化,

可以看到_vfptr[0]存放的是被重寫后的Func1的地址。

所以就可以下一個簡單的結論:

派生類先繼承基類的虛表,

如果派生類重寫了基類中某個虛函數(shù),

用派生類自己的虛函數(shù)覆蓋虛表中基類的虛函數(shù)。

那派生類自己的虛函數(shù)呢?

按理來說派生類有虛函數(shù),

實例化出來的對象也應該有一個虛基表,

但是這里好像并不是這樣。

實際上,

派生類自己新增加的虛函數(shù),

會按其在派生類中的聲明次序增加到基類虛表的最后,

和基類共用一個虛表。

而這里繼承的基類的虛表沒有顯示出派生類的虛函數(shù),

這是編譯器的監(jiān)視窗口故意隱藏了這個函數(shù),

也可以認為是他的一個小bug。

那么我們如何查看d的虛表呢?


打印虛表

我們既然有虛表指針_vfptr,

那我們肯定就有辦法打印它指向的虛表的內容,

也就是各個虛函數(shù)的地址。

下面就來看一下怎樣獲取。

首先在對象的存儲結構中虛表指針存放在最上面,

也就是對象頭四個字節(jié)(64位指針是八個字節(jié)),

所以對象模型如下:

因為我們最終要訪問的指針類型是函數(shù)指針,

所以我們可以先typedef一下這個函數(shù)指針類型:

typedef void(*VFPTR)()

我們先取d的地址:&d,

&d此時的類型是Derive*

我們需要對其進行類型轉換,

我們看到_vfptr的類型是void**,

所以對其進行類型轉換:(void**)&d,

void*在32位平臺下是4個字節(jié),64位平臺下是8個字節(jié),

所以對void**解引用就可以訪問頭4/8個字節(jié)的空間。

然后對其解引用找到虛表:*(void**)&d

此時就拿到了虛表指針,但它的類型是void*,

而虛表是一個函數(shù)指針數(shù)組,

所以我們再做一次類型轉換就拿到了可以訪問數(shù)組元素的虛表指針:(VFPTR*)(*(void**)&d),

所以我們就可以通過下標訪問訪問到函數(shù)指針:((VFPTR*)(*(void**)&d))[0] -> Derive::Func1(),

我們還可以通過拿到的函數(shù)指針調用函數(shù):((VFPTR*)(*(void**)&d))[0]()。

所以現(xiàn)在我們可以通過下面的代碼遍歷虛表,

打印虛表中存放的函數(shù)指針,

并通過函數(shù)指針調用函數(shù),

看看是哪個函數(shù):

for (int i = 0; i < n; i++)  // n是虛表中有幾個函數(shù)指針
{
    cout << ((VFPTR*)(*(void**)&d))[i] << "->";
    ((VFPTR*)(*(void**)&d))[i]();
}

這里有三個虛函數(shù),所以n就是3

運行結果如下:

驗證了此前所說的。

我們還可以看一下基類對象的虛表:


多繼承中的虛表

看下面的代碼:

class Base1 
{
public:
	virtual void func1() 
    { cout << "Base1::func1" << endl; }
    
	virtual void func2() 
    { cout << "Base1::func2" << endl; }
    
private:
	int _b1 = 1;
};

class Base2 
{
public:
	virtual void func1() 
    { cout << "Base2::func1" << endl; }
    
	virtual void func2() 
    { cout << "Base2::func2" << endl; }
    
private:
	int _b2 = 2;
};

class Derive : public Base1, public Base2 
{
public:
	virtual void func1() 
    { cout << "Derive::func1" << endl; }
    
	virtual void func3()
    { cout << "Derive::func3" << endl; }
    
private:
	int _d1 = 3;
};

此時派生類是繼承了兩個基類的派生類,

那它現(xiàn)在的對象模型是怎樣的呢?

可以看到普通多繼承的場景下它完整繼承了兩個基類的虛表指針,

兩個基類中都有Func1函數(shù),

可以看到此時Func1函數(shù)都被重寫后的函數(shù)覆蓋了。

那派生類它自己的虛函數(shù)呢?

這里直接給出結論:多繼承派生類的虛函數(shù)放在第一個繼承基類部分的虛函數(shù)表中。

所以第一個虛表中存放了三個函數(shù)指針,

分別指向Derive::Func1(),Base1::Func2(),Derive::Func3(),

第二個虛表中存放了兩個函數(shù)指針,

分別指向Derive::Func1()Base2::Func2()。

所以對象模型如下:

可以通過打印虛表來驗證一下。

這里直接對d取地址可以拿到Base1::_vfptr,

但是要怎么拿到Base2::_vfptr呢?

我們可以直接讓指針偏移sizeof(Base1)個字節(jié),

也就是把&d改為(char*)&d + sizeof(Base1),

結果如下:


虛表的存儲

我們現(xiàn)在再明確一下概念,

虛函數(shù)是函數(shù),

和普通函數(shù)一樣,

存放在代碼段。

虛表是一個指針數(shù)組,

存放指向虛函數(shù)的指針。

而類實例化出來的對象中存放的是一個虛表指針,

是指向虛表的指針。

所以對象中虛表指針存放在哪是很明確的,

就看對象存放在哪,

對象在棧上,那它的虛表指針也在棧上,

對象在堆上,那它的虛表指針就在堆上。

那問題來了,虛表存在哪呢?

我們可以通過一個簡單的比對來看看:

Derive d;
Derive* pd = new Derive;

cout << "棧: " << &d << endl;

Derive* pd = new Derive;
cout << "堆: " << pd << endl;

cout << "代碼段: " << ((VFPTR*)(*(void**)&d))[0] << endl;

cout << "d的虛表地址: " << (void*)*(void**)&d << endl;

cout << "pd的虛表地址: " << (void*)*(void**)pd << endl;

棧、堆、代碼段上的空間都是連續(xù)的,

我們我們可以將虛表的地址和它們進行比較:

【C++】面向對象之多態(tài)

通過對比可以發(fā)現(xiàn)虛表是存放在代碼段的,

而且無論是臨時對象還是動態(tài)開辟的對象,

都是共用一個虛表。

當一個c++程序編譯成可執(zhí)行程序之后,

此時虛表已經形成了,

和函數(shù)一樣存放在代碼段。

當我們實例化對象時,

對應的構造函數(shù)會對對象的虛表指針進行初始化,

將虛表的地址寫入到虛表指針中,

所以虛表是編譯完就有了的,

而虛表指針是運行時才有的。


多態(tài)的原理

前面我們看了虛函數(shù)表,

那這個虛函數(shù)表和多態(tài)調用有什么密不可分的關系嗎?

下面以文章開頭的那段代碼為例進行講解:

class Person
{
public:
	virtual void BuyTicket()
	{ cout << "原價買票" << endl; }
};

class Student : public Person
{
public:
	virtual void BuyTicket()
    { cout << "半價買票" << endl; }
};

class Solider : public Person
{
public:
	virtual void BuyTicket()
	{ cout << "優(yōu)先買票" << endl; }
};

void QueryPriority(Person* p)
{ p->BuyTicket(); }

int main()
{
	Person p;
	Student stu;
    Solider solider;
    
    QueryPriority(&p);
	QueryPriority(&stu);
	QueryPriority(&solider);

	return 0;
}

首先我們有一個基類指針,

當我們使用這個指針去調用虛函數(shù)時,

會去訪問這個基類指針指向的對象的虛表指針,

然后通過虛表指針找到虛表,

在虛表中找到對應的函數(shù)然后調用。

如果調用的函數(shù)不存在于虛表中,

則會發(fā)生報錯,

最簡單的就是使用基類指針去調用派生類自己定義的虛函數(shù)。

在文章虛表的存儲部分最后說了,

對象的虛表指針是在構造函數(shù)中初始化的,是運行時才有的,

在程序運行期間,

根據(jù)具體拿到的類型確定程序的具體行為,

調用具體的函數(shù),

這就是所謂的動態(tài)綁定,也叫動態(tài)多態(tài)。

我們可以通過匯編代碼看一下普通調用和多態(tài)調用時的區(qū)別:
【C++】面向對象之多態(tài)

與動態(tài)綁定相對的是靜態(tài)綁定,也叫靜態(tài)多態(tài),

我們常用的函數(shù)重載就是一種靜態(tài)多態(tài),

是在在程序編譯期間確定了程序的行為。


幾個小問題

  1. 內聯(lián)函數(shù)(inline)可以是虛函數(shù)嗎?
    可以。
    不過編譯器就忽略inline屬性,
    這個函數(shù)就不再是inline,
    因為虛函數(shù)要放到虛表中去。

  2. 靜態(tài)成員可以是虛函數(shù)嗎?
    不能。
    因為靜態(tài)成員函數(shù)沒有this指針,
    使用類型::成員函數(shù)的調用方式無法訪問虛函數(shù)表,
    所以靜態(tài)成員函數(shù)無法放進虛函數(shù)表

  3. 構造函數(shù)可以是虛函數(shù)嗎?
    不能。
    因為對象中的虛函數(shù)表指針是在構造函數(shù)初始化列表階段才初始化的。
    如果構造函數(shù)定義成虛函數(shù),
    那想調用構造函數(shù)就要去虛函數(shù)表中尋找,
    而虛表指針還沒有初始化,
    就找不到構造函數(shù)了。

  4. 對象訪問普通函數(shù)快還是虛函數(shù)更快?
    首先如果是通過"對象.函數(shù)"的方式去調用,
    是一樣快的。
    如果是指針對象或者是引用對象,
    則調用的普通函數(shù)快,
    因為調用虛函數(shù)時還需要先到虛函數(shù)表中去查找。文章來源地址http://www.zghlxwxcb.cn/news/detail-428451.html

到了這里,關于【C++】面向對象之多態(tài)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • C++:多態(tài)究竟是什么?為何能成為面向對象的重要手段之一?

    C++:多態(tài)究竟是什么?為何能成為面向對象的重要手段之一?

    本篇博客基于VS2019X86環(huán)境下,后續(xù)關于多態(tài)原理相關驗證都是基于vsX86環(huán)境,而虛表本質上是一個虛函數(shù)指針數(shù)組,在X86環(huán)境下VS編譯器會在數(shù)組最后放一個unllptr?。?多態(tài)的概念:通俗來說,就是多種形態(tài),具體點就是去 完成某個行為,當不同的對象去完成時會產生出不同的

    2024年02月02日
    瀏覽(19)
  • c、c++、java、python、js對比【面向對象、過程;解釋、編譯語言;封裝、繼承、多態(tài)】

    c、c++、java、python、js對比【面向對象、過程;解釋、編譯語言;封裝、繼承、多態(tài)】

    目錄 內存管理、適用 區(qū)別 C 手動內存管理:C語言沒有內置的安全檢查機制,容易出現(xiàn)內存泄漏、緩沖區(qū)溢出等安全問題。 適用于系統(tǒng)級編程 C++ 手動內存管理:C++需要程序員手動管理內存,包括分配和釋放內存,這可能導致內存泄漏和指針錯誤。 適用于游戲引擎和系統(tǒng)級編

    2024年02月08日
    瀏覽(51)
  • 【C++庖丁解?!棵嫦驅ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關系中的虛函數(shù)表

    【C++庖丁解?!棵嫦驅ο蟮娜筇匦灾欢鄳B(tài) | 抽象類 | 多態(tài)的原理 | 單繼承和多繼承關系中的虛函數(shù)表

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結構、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油 需要聲明的,本節(jié)課件中的代碼及解釋都是在vs2013下的x86程序中,涉及的指針都是4bytes。如果要其他平臺

    2024年04月10日
    瀏覽(28)
  • 面向對象詳解,面向對象的三大特征:封裝、繼承、多態(tài)

    面向對象詳解,面向對象的三大特征:封裝、繼承、多態(tài)

    一、面向對象與面向過程 面向對象編程 (Object-Oriented Programming,簡稱OOP)和 面向過程編程 (Procedural Programming,簡稱PP)是兩種不同的 編程范式 。 面向對象編程強調把問題分解成對象,通過封裝、繼承和多態(tài)等機制,來處理對象之間的關系 。每個對象都可以獨立地處理自

    2024年02月21日
    瀏覽(23)
  • 面向對象——多態(tài)、抽象類、接口

    面向對象——多態(tài)、抽象類、接口

    學習資料來自:黑馬程序員,內容僅為學習記錄,侵刪 多態(tài) 多態(tài):事務存在的多種形態(tài) 多態(tài)的前提:1、有繼承關系;2、重寫父類方法;3、父類引用指向子類對象 面向對象 面向對象多態(tài)中成員訪問特點 1.成員方法(動態(tài)綁定):編譯看左邊(父類),運行看右邊(子類)

    2024年02月08日
    瀏覽(28)
  • 面向對象的多態(tài)

    面向對象的多態(tài)

    7. 面向對象特征三:多態(tài)性 概念: 多態(tài)是面向對象程序設計(OOP)的一個重要特征,指同一個實體同時具有多種形式, 女朋友養(yǎng)寵物 王者榮耀英雄 7.1 多態(tài)的形式和體現(xiàn) 7.1.1 對象的多態(tài)性 多態(tài)性,是面向對象中最重要的概念, 在 Java 中如何體現(xiàn)的:對象的多態(tài)性:父類的

    2024年02月08日
    瀏覽(37)
  • Java面向對象多態(tài)

    目錄 多態(tài)概述 Java 多態(tài)包括以下三種方式 方法重寫(Override) 向上轉型(Upcasting) 實現(xiàn)多態(tài) Java 多態(tài)是指同一種類型的對象,在不同的情況下有著不同的狀態(tài)和行為。它是基于繼承、重寫和向上轉型等特性實現(xiàn)的,多態(tài)是面向對象編程的三大特征之一,其他兩個分別是封裝

    2023年04月13日
    瀏覽(20)
  • 【JavaSE】面向對象之多態(tài)

    【JavaSE】面向對象之多態(tài)

    通俗來說,就是多種形態(tài),具體點就是去完成某個行為,當不同的對象去完成時會產生出不同的狀態(tài)。 必須要滿足如下幾個條件,缺一不可: 必須在 繼承 體系下 子類必須要對父類中方法進行 重寫 通過父類的引用調用重寫的方法 定義測試類TestAnimal.java 編譯器在編譯代碼時

    2024年02月11日
    瀏覽(25)
  • 【面向對象語言三大特性之 “多態(tài)”】

    【面向對象語言三大特性之 “多態(tài)”】

    目錄 ?1. 多態(tài)的概念 1.1 概念 2. 多態(tài)的定義及實現(xiàn) 2.1多態(tài)的構成條件 2.2 虛函數(shù) ?2.3虛函數(shù)的重寫 2.4 C++11 override 和 final ?2.5 重載、覆蓋(重寫)、隱藏(重定義)的對比 ?3. 抽象類 3.1 概念 3.2 接口繼承和實現(xiàn)繼承 ?4.多態(tài)的原理 4.1虛函數(shù)表 ?4.2多態(tài)的原理 4.3 動態(tài)綁定與靜態(tài)綁定

    2023年04月17日
    瀏覽(56)
  • 面向對象(類/繼承/封裝/多態(tài))詳解

    面向對象(類/繼承/封裝/多態(tài))詳解

    面向對象編程(Object-Oriented Programming,OOP)是一種廣泛應用于軟件開發(fā)的編程范式。它基于一系列核心概念,包括類、繼承、封裝和多態(tài)。在這篇詳細的解釋中,我們將探討這些概念,并說明它們如何在PHP等編程語言中實現(xiàn)。 類是OOP的基礎。它是一種用于創(chuàng)建對象的藍圖或模

    2024年02月08日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包