91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中Virtual的用法

發布時間:2021-08-19 09:59:44 來源:億速云 閱讀:153 作者:chen 欄目:軟件技術

本篇內容介紹了“C++中Virtual的用法”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Virtual是C++ OO機制中很重要的一個關鍵字。只要是學過C++的人都知道在類Base中加了Virtual關鍵字的函數就是虛擬函數(例如函數print),于是在Base的派生類Derived中就可以通過重寫虛擬函數來實現對基類虛擬函數的覆蓋。當基類Base的指針point指向派生類Derived的對象時,對point的print函數的調用實際上是調用了Derived的print函數而不是Base的print函數。這是面向對象中的多態性的體現。(關于虛擬機制是如何實現的,參見Inside the C++ Object Model ,Addison Wesley 1996)
class Base
{
public:Base(){}
public:
       virtual void print(){cout<<"Base";}
};
 
class Derived:public Base
{
public:Derived(){}
public:
       void print(){cout<<"Derived";}
};
 
int main()
{
       Base *point=new Derived();
       point->print();
}

Output:
Derived
這也許會使人聯想到函數的重載,但稍加對比就會發現兩者是完全不同的:
(1)       重載的幾個函數必須在同一個類中;
覆蓋的函數必須在有繼承關系的不同的類中
(2)       覆蓋的幾個函數必須函數名、參數、返回值都相同;
重載的函數必須函數名相同,參數不同。參數不同的目的就是為了在函數調用的時候編譯器能夠通過參數來判斷程序是在調用的哪個函數。這也就很自然地解釋了為什么函數不能通過返回值不同來重載,因為程序在調用函數時很有可能不關心返回值,編譯器就無法從代碼中看出程序在調用的是哪個函數了。
(3)       覆蓋的函數前必須加關鍵字Virtual;
重載和Virtual沒有任何瓜葛,加不加都不影響重載的運作。
 
關于C++的隱藏規則:
我曾經聽說過C++的隱藏規則:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual
關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,并且參數也相同,但是基類函數沒有virtual
關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。
#include <iostream.h>
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
 
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
 
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}
 
bp 和dp 指向同一地址,按理說運行結果應該是相同的,而事實上運行結果不同,所以他把原因歸結為C++的隱藏規則,其實這一觀點是錯的。決定bp和dp調用函數運行結果的不是他們指向的地址,而是他們的指針類型。“只有在通過基類指針或引用間接指向派生類子類型時多態性才會起作用”(C++ Primer 3rd Edition)。pb是基類指針,pd是派生類指針,pd的所有函數調用都只是調用自己的函數,和多態性無關,所以pd的所有函數調用的結果都輸出Derived::是完全正常的;pb的函數調用如果有virtual則根據多態性調用派生類的,如果沒有virtual則是正常的靜態函數調用,還是調用基類的,所以有virtual的f函數調用輸出Derived::,其它兩個沒有virtual則還是輸出Base::很正常啊,nothing surprise!
所以并沒有所謂的隱藏規則,雖然《高質量C++/C 編程指南》是本很不錯的書,可大家不要迷信哦。記住“只有在通過基類指針或引用間接指向派生類子類型時多態性才會起作用”。
 
純虛函數:
C++語言為我們提供了一種語法結構,通過它可以指明,一個虛擬函數只是提供了一個可被子類型改寫的接口。但是,它本身并不能通過虛擬機制被調用。這就是純虛擬函數(pure
virtual function)。 純虛擬函數的聲明如下所示:
class Query {
public:
// 聲明純虛擬函數
virtual ostream& print( ostream&=cout ) const = 0;
// ...
};
這里函數聲明后面緊跟賦值0。
包含(或繼承)一個或多個純虛擬函數的類被編譯器識別為抽象基類。試圖創建一個抽象基類的獨立類對象會導致編譯時刻錯誤。(類似地通過虛擬機制調用純虛擬函數也是錯誤的例如)
// Query 聲明了純虛擬函數
// 所以, 程序員不能創建獨立的 Query 類對象
// ok: NameQuery 中的 Query 子對象
Query *pq = new NameQuery( "Nostromo" );
// 錯誤: new 表達式分配 Query 對象
Query *pq2 = new Query;
抽象基類只能作為子對象出現在后續的派生類中。
 
如果只知道virtual加在函數前,那對virtual只了解了一半,virtual還有一個重要用法是virtual public,就是虛擬繼承。虛擬繼承在C++ Primer中有詳細的描述,下面稍作修改的闡釋一下:
在缺省情況下C++中的繼承是“按值組合”的一種特殊情況。當我們寫
class Bear : public ZooAnimal { ... };
每個Bear 類對象都含有其ZooAnimal 基類子對象的所有非靜態數據成員以及在Bear中聲明的非靜態數據成員類似地當派生類自己也作為一個基類對象時如:
class PolarBear : public Bear { ... };
則PolarBear 類對象含有在PolarBear 中聲明的所有非靜態數據成員以及其Bear 子對象的所有非靜態數據成員和ZooAnimal 子對象的所有非靜態數據成員。在單繼承下這種由繼承支持的特殊形式的按值組合提供了最有效的最緊湊的對象表示。在多繼承下當一個基類在派生層次中出現多次時就會有問題最主要的實際例子是iostream 類層次結構。ostream 和istream 類都從抽象ios 基類派生而來,而iostream 類又是從ostream 和istream 派生
class iostream :public istream, public ostream { ... };
缺省情況下,每個iostream 類對象含有兩個ios 子對象:在istream 子對象中的實例以及在ostream 子對象中的實例。這為什么不好?從效率上而言,存儲ios 子對象的兩個復本,浪費了存儲區,因為iostream 只需要一個實例。而且,ios 構造函數被調用了兩次每個子對象一次。更嚴重的問題是由于兩個實例引起的二義性。例如,任何未限定修飾地訪問ios 的成員都將導致編譯時刻錯誤:到底訪問哪個實例?如果ostream 和istream 對其ios 子對象的初始化稍稍不同,會怎樣呢?怎樣通過iostream 類保證這一對ios 值的一致性?在缺省的按值組合機制下,真的沒有好辦法可以保證這一點。
C++語言的解決方案是,提供另一種可替代按“引用組合”的繼承機制虛擬繼承(virtual inheritance )在虛擬繼承下只有一個共享的基類子對象被繼承而無論該基類在派生層次
中出現多少次共享的基類子對象被稱為虛擬基類。
       通過用關鍵字virtual 修政一個基類的聲明可以將它指定為被虛擬派生。例如,下列聲明使得ZooAnimal 成為Bear 和Raccoon 的虛擬基類:
// 關鍵字 public 和 virtual
// 的順序不重要
class Bear : public virtual ZooAnimal { ... };
class Raccoon : virtual public ZooAnimal { ... };
虛擬派生不是基類本身的一個顯式特性,而是它與派生類的關系如前面所說明的,虛擬繼承提供了“按引用組合”。也就是說,對于子對象及其非靜態成員的訪問是間接進行的。這使得在多繼承情況下,把多個虛擬基類子對象組合成派生類中的一個共享實例,從而提供了必要的靈活性。同時,即使一個基類是虛擬的,我們仍然可以通過該基類類型的指針或引用,來操縱派生類的對象。

“C++中Virtual的用法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

淮南市| 循化| 莱阳市| 建水县| 沽源县| 城口县| 梨树县| 溧阳市| 高阳县| 株洲市| 廊坊市| 阜宁县| 大埔区| 左云县| 兴山县| 道孚县| 台湾省| 开鲁县| 大连市| 明光市| 彭泽县| 隆回县| 民丰县| 扎赉特旗| 孝感市| 宜阳县| 滁州市| 广宗县| 鄂伦春自治旗| 龙江县| 芷江| 商洛市| 芮城县| 新民市| 泗水县| 石林| 沙坪坝区| 南阳市| 丘北县| 资讯| 凤山市|